CVE-2017-20172: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') (CWE-89)
value: A vulnerability was found in ridhoq soundslike. It has been classified as critical. Affected is the function get_song_relations of the file app/api/songs.py. The manipulation leads to sql injection. The patch is identified as 90bb4fb667d9253d497b619b9adaac83bf0ce0f8. It is recommended to apply a patch to fix this issue. VDB-218490 is the identifier assigned to this vulnerability.
CWE description: The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data.
CVSS v3 base score: 9.8
Published: 2023-01-18T15:15Z
Repository: https://github.com/ridhoq/soundslike
Language: Python
Files changed: app/api/songs.py, test/api/test_song_relations.py
Commit date: 2017-03-17 19:48:53 -0500
Commit message: fix sql injection vulnerability in get_song_relations 😅

Diff: diff --git a/app/api/songs.py b/app/api/songs.py
index ed45f17..62b0387 100644
--- a/app/api/songs.py
+++ b/app/api/songs.py
@@ -60,11 +60,15 @@ def new_song():
         message = 'that aint json'
         return bad_request(message)
 
 @api.route('/songs/<int:id>/related')
 def get_song_relations(id):
-    top = request.args.get('top')
+    top_str = request.args.get('top')
+    if not top_str.isdigit() or not int(top_str) > 0:
+        message = 'top query param must be an int greater than 0'
+        return bad_request(message)
+    top = int(request.args.get('top'))
     song = Song.query.filter_by(id=id).first()
     if not song:
         return route_not_found(song)
     return make_response(jsonify(song.get_related_songs_json(top)), 200)
 
diff --git a/test/api/test_song_relations.py b/test/api/test_song_relations.py
index 581ddda..933e703 100644
--- a/test/api/test_song_relations.py
+++ b/test/api/test_song_relations.py
@@ -329,5 +329,24 @@ class TestSongRelationsApi():
                               content_type='application/json')
         assert res.status_code == 200
         assert len(res.json) == 1
         assert res.json[0]['id'] == self.songs['edm'][1]['id']
 
+    def test_get_song_relations_top_query_param(self):
+        song_id = self.songs['edm'][0]['id']
+        res = self.client.get(url_for('api.get_song_relations', id=song_id, top=0),
+                              content_type='application/json')
+        assert res.status_code == 400
+        assert res.json['error'] == 'bad request'
+        assert res.json['message'] == 'top query param must be an int greater than 0'
+
+        res = self.client.get(url_for('api.get_song_relations', id=song_id, top=-1),
+                              content_type='application/json')
+        assert res.status_code == 400
+        assert res.json['error'] == 'bad request'
+        assert res.json['message'] == 'top query param must be an int greater than 0'
+
+        res = self.client.get(url_for('api.get_song_relations', id=song_id, top='10; select * from users'),
+                              content_type='application/json')
+        assert res.status_code == 400
+        assert res.json['error'] == 'bad request'
+        assert res.json['message'] == 'top query param must be an int greater than 0'

Vulnerable code:     top = request.args.get('top')
Fixed code:     top_str = request.args.get('top')
    if not top_str.isdigit() or not int(top_str) > 0:
        message = 'top query param must be an int greater than 0'
        return bad_request(message)
    top = int(request.args.get('top'))
    def test_get_song_relations_top_query_param(self):
        song_id = self.songs['edm'][0]['id']
        res = self.client.get(url_for('api.get_song_relations', id=song_id, top=0),
                              content_type='application/json')
        assert res.status_code == 400
        assert res.json['error'] == 'bad request'
        assert res.json['message'] == 'top query param must be an int greater than 0'

        res = self.client.get(url_for('api.get_song_relations', id=song_id, top=-1),
                              content_type='application/json')
        assert res.status_code == 400
        assert res.json['error'] == 'bad request'
        assert res.json['message'] == 'top query param must be an int greater than 0'

        res = self.client.get(url_for('api.get_song_relations', id=song_id, top='10; select * from users'),
                              content_type='application/json')
        assert res.status_code == 400
        assert res.json['error'] == 'bad request'
        assert res.json['message'] == 'top query param must be an int greater than 0'