Page MenuHomePhabricator

Reflected Cross-Site scripting (XSS) vulnerability in analytics-quarry-web
Closed, ResolvedPublicSecurity

Description

From security@ email

GitHub Security Lab (GHSL) Vulnerability Report: GHSL-2020-336
The GitHub Security Lab team has identified potential security vulnerabilities in wikimedia/analytics-quarry-web.

We are committed to working with you to help resolve these issues. In this report you will find everything you need to effectively coordinate a resolution of these issues with the GHSL team.

If at any point you have concerns or questions about this process, please do not hesitate to reach out to us at securitylab@github.com (please include GHSL-2020-336 as a reference).

If you are NOT the correct point of contact for this report, please let us know!

Summary
A reflected Cross-Site scripting (XSS) vulnerability has been found in analytics-quarry-web

Product
https://github.com/wikimedia/analytics-quarry-web

Tested Version
Latest commit at the time of reporting (December 14, 2020).

Details
The server responds with return Response(json.dumps(...)) without setting proper mime-type (application/json).

This becomes problematic for the preference handling defined here: https://github.com/wikimedia/analytics-quarry-web/blob/085a51b2dee8b58882276d9fe090174252edb85e/quarry/web/app.py#L395-L412

You can exploit this vulnerability by tricking a logged in user to visit vulnerable URL.

PoC:

Visit official Quarry site https://quarry.wmflabs.org/ or follow setup instructions on repo. (I found official site from here)
Log in with a wiki-media acocunt
Visit vulnerable URL: https://quarry.wmflabs.org/api/preferences/get/%3Cimg%20src=0%20onerror=alert(0)%3E
Impact
XSS can cause a variety of problems for the end user that range in severity from an annoyance to complete account compromise. The most severe XSS attacks involve disclosure of the user’s session cookie, allowing an attacker to hijack the user’s session and take over the account.

GitHub Security Advisories
We recommend you create a private GitHub Security Advisory for these findings. This also allows you to invite the GHSL team to collaborate and further discuss these findings in private before they are published.

Credit
This issue was discovered and reported by CodeQL Python team.

Contact
You can contact the GHSL team at securitylab@github.com, please include GHSL-2020-336 in any communication regarding this issue.

Disclosure Policy
This report is subject to our coordinated disclosure policy.

Event Timeline

Is the fix really as simple as this?

diff --git a/quarry/web/app.py b/quarry/web/app.py
index 13251eb..31c426b 100644
--- a/quarry/web/app.py
+++ b/quarry/web/app.py
@@ -398,9 +398,9 @@ def pref_get(key):
         return "Authentication required", 401
 
     if key in get_preferences():
-        return Response(json.dumps({'key': key, 'value': get_preferences()[key]}))
+        return Response(json.dumps({'key': key, 'value': get_preferences()[key]}),mimetype='application/json',content_type='application/json; charset=utf-8')
     else:
-        return Response(json.dumps({'key': key, 'error': 'novalue'}))
+        return Response(json.dumps({'key': key, 'error': 'novalue'}),mimetype='application/json',content_type='application/json; charset=utf-8')
 
 
 @app.route("/api/preferences/set/<key>/<value>")
@@ -409,7 +409,7 @@ def pref_set(key, value):
         return "Authentication required", 401
 
     get_preferences()[key] = (None if value == 'null' else value)
-    return Response(json.dumps({'key': key, 'success': ''})), 201
+    return Response(json.dumps({'key': key, 'success': ''}),mimetype='application/json',content_type='application/json; charset=utf-8'), 201
 
 
 if __name__ == '__main__':

Is the fix really as simple as this?

Probably :)

Reedy triaged this task as High priority.Dec 15 2020, 4:59 PM

I guess the content type is superfluous (and not present in other code in the file)

commit bb83dad383a5d3c8ce5c21d28b6522c42ebc1668 (HEAD -> master)
Author: Reedy <reedy@wikimedia.org>
Date:   Tue Dec 15 16:55:55 2020 +0000

    SECURITY: Set correct Content-Type/Mime Type on /api/preferences
    
    Prevents a Reflected Cross-Site scripting (XSS) vulnerability
    
    Bug: T270195

diff --git a/quarry/web/app.py b/quarry/web/app.py
index 13251eb..845a60f 100644
--- a/quarry/web/app.py
+++ b/quarry/web/app.py
@@ -398,9 +398,15 @@ def pref_get(key):
         return "Authentication required", 401
 
     if key in get_preferences():
-        return Response(json.dumps({'key': key, 'value': get_preferences()[key]}))
+        return Response(
+            json.dumps({'key': key, 'value': get_preferences()[key]}),
+            mimetype='application/json'
+        )
     else:
-        return Response(json.dumps({'key': key, 'error': 'novalue'}))
+        return Response(
+            json.dumps({'key': key, 'error': 'novalue'}),
+            mimetype='application/json'
+        )
 
 
 @app.route("/api/preferences/set/<key>/<value>")
@@ -409,7 +415,10 @@ def pref_set(key, value):
         return "Authentication required", 401
 
     get_preferences()[key] = (None if value == 'null' else value)
-    return Response(json.dumps({'key': key, 'success': ''})), 201
+    return Response(
+        json.dumps({'key': key, 'success': ''}),
+        mimetype='application/json'
+    ), 201
 
 
 if __name__ == '__main__':

Patch deployed... XSS seems to be fixed

Change 649711 had a related patch set uploaded (by Reedy; owner: Reedy):
[analytics/quarry/web@master] SECURITY: Set correct Mime Type on /api/preferences

https://gerrit.wikimedia.org/r/649711

Change 649711 merged by jenkins-bot:
[analytics/quarry/web@master] SECURITY: Set correct Mime Type on /api/preferences

https://gerrit.wikimedia.org/r/649711

Reedy claimed this task.

Pulled onto hosts, workers restarted

Reedy changed the visibility from "Custom Policy" to "Public (No Login Required)".Dec 15 2020, 5:44 PM
Reedy changed the edit policy from "Custom Policy" to "All Users".

I have just read this ticket, sorry for the code I added and thanks for the remediation.