Spotipy is one of the most popular, lightweight Python wrappers around the Spotify Web API. Developers love its simple interface for searching tracks, playlists, users, and more. But sometimes, even the best libraries can hide dangerous flaws if they're carelessly handling user input.

That's exactly what happened in CVE-2023-23608, a subtle but serious vulnerability affecting all Spotipy versions before 2.22.1. Below, we’ll break down what happened in simple language, show the affected code with examples, and explain how attackers can exploit the bug. This content is unique and written to help all programmers understand what went wrong — whether you use Spotipy or not.

What is CVE-2023-23608?

In short: Spotipy’s URI and URL parsing functions fail to sanitize or properly restrict path inputs, allowing attackers to smuggle special characters (like "..") into API requests. When a user supplies a malicious Spotify URI, Spotipy could be tricked into performing a totally different API call than what the developer intended.

Official Advisory

- GitHub Security Advisory GHSA-h2xm-6h5p-gwcx
- NIST NVD Entry - CVE-2023-23608

Spotipy quickly fixed this in version 2.22.1 by improving URI and URL handling.

How Spotipy Normally Works

Let’s remember how Spotipy expects to be used. Normally, you’ll pass in Spotify-specific URIs or URLs—like a track or playlist identifier—to helper functions like spotify.track() or spotify.playlist(). Spotipy parses your input and builds an API request for you.

Good Input Example

import spotipy
from spotipy.oauth2 import SpotifyClientCredentials

sp = spotipy.Spotify(auth_manager=SpotifyClientCredentials())
track_info = sp.track("spotify:track:3n3Ppam7vgaVa1iaRUc9Lp")
print(track_info['name'])  # Should print the track name correctly

But behind the scenes, Spotipy *trusts* the value you give. There’s very little input filtering, which is a problem if someone can supply their own URIs.

Dissecting the Flawed Logic

In vulnerable versions of Spotipy, code that parses URIs fails to check for malicious path changes. Here’s a simplified version of the relevant logic (not actual Spotipy code, but illustrative):

def parse_uri(uri):
    # Accepts URIs like spotify:track:TRACK_ID
    parts = uri.split(':')
    if parts[] == 'spotify':
        resource = parts[1]
        resource_id = parts[2]
        path = f"/v1/{resource}s/{resource_id}"  # e.g., /v1/tracks/3n3Ppam7vgaVa1iaRUc9Lp
        return path

What’s missing?
No filtering for "..", additional slashes, or unexpected characters.

So, what if we hand it a strange (but valid) looking Spotify URI?

Suppose a malicious user enters

spotify:track:../playlists/37i9dQZF1DXcBWIGoYBM5M

The code splits and parses the URI.

2. "../playlists/37i9dQZF1DXcBWIGoYBM5M" replaces the track ID.

`

/v1/tracks/../playlists/37i9dQZF1DXcBWIGoYBM5M

`

/v1/playlists/37i9dQZF1DXcBWIGoYBM5M

Pseudocode Reproduction

# Vulnerable code
resource = "track"
user_input = "../playlists/37i9dQZF1DXcBWIGoYBM5M"
endpoint = f"/v1/{resource}s/{user_input}"
print(endpoint)  # Prints: /v1/tracks/../playlists/37i9dQZF1DXcBWIGoYBM5M

# After normalization by the remote API or client:
normalized = "/v1/playlists/37i9dQZF1DXcBWIGoYBM5M"

Data Confusion:

Your app thinks it’s showing details of a track, but it’s actually showing info from a playlist, album, or another user’s data. This can:

API Abuse:

Attackers can probe and misuse different endpoints, possibly impacting user accounts, if your access tokens are powerful enough.

Here’s a worked example using the vulnerable Spotipy version

import spotipy
from spotipy.oauth2 import SpotifyClientCredentials

sp = spotipy.Spotify(auth_manager=SpotifyClientCredentials())

# The attacker supplies a malicious 'track' URI
mal_uri = "spotify:track:../playlists/37i9dQZF1DXcBWIGoYBM5M"
result = sp.track(mal_uri)

print(result)  # Actually contains playlist info, not track info!

If your app then directly displays or trusts this info, you could show playlist metadata in a “track” area, possibly causing logic errors or leaks.

Mitigation Status

Fixed in Spotipy v2.22.1.  
Code now checks for malicious path changes and refuses bad URIs.

If you use Spotipy, upgrade immediately:

pip install --upgrade spotipy

Or, at least, always validate and sanitize any URIs coming from users.

Final Thoughts

This is a great example of why even small parsing bugs can become major security issues. If a library turns *any* part of user input into API requests, it should strictly validate that input.

Spotipy’s maintainers were quick to patch. The real risk is for custom applications that trust Spotify URIs from untrusted sources.

Resources

- Spotipy Repo + Security Advisories
- CVE-2023-23608 on MITRE/CVE

Stay aware of open source bugs! Share this with your team — it might just save you from a nasty data leak or feature confusion down the line.

Timeline

Published on: 01/26/2023 21:18:00 UTC
Last modified on: 02/06/2023 17:23:00 UTC