GHSA-6p96-cfg5-4vhp: Koel: Authenticated Full-Read SSRF via Subsonic Internet Radio Stations
Summary
Koel v9.6.0 validates radio station URLs on the regular web API, but the Subsonic-compatible radio endpoints do not apply the same SSRF protections. An authenticated user can create or update a radio station with a private URL and then use Koel's radio streaming feature to make the server fetch that URL and return the upstream response body.
This was validated against v9.6.0 (352ea5ec27fa22294da8fb6beacb3d5552f0d09c) using the official phanan/koel:9.6.0 image.
Details
SafeUrl is applied on the web API, but not on the Subsonic endpoints
Koel's regular radio API protects station URLs with SafeUrl and HasAudioContentType:
- app/Http/Requests/API/Radio/RadioStationStoreRequest.php
- app/Http/Requests/API/Radio/RadioStationUpdateRequest.php
new SafeUrl(),
new HasAudioContentType(),
The Subsonic-compatible routes do not reuse those checks:
- routes/subsonic.php
- createInternetRadioStation.view
- updateInternetRadioStation.view
- app/Http/Requests/Subsonic/CreateInternetRadioStationRequest.php
- app/Http/Requests/Subsonic/UpdateInternetRadioStationRequest.php
return [
'streamUrl' => ['required', 'string'],
'name' => ['required', 'string'],
'homepageUrl' => ['nullable', 'string'],
];
The result is a validation gap between two routes that create the same type of object.
The unvalidated URL is stored and later fetched server-side
The Subsonic controllers hand the supplied URL to the regular radio service without any SSRF validation:
- app/Http/Controllers/Subsonic/CreateInternetRadioStationController.php
- app/Http/Controllers/Subsonic/UpdateInternetRadioStationController.php
- app/Services/RadioService.php
The SSRF is triggered when the station is played:
- app/Http/Controllers/StreamRadioController.php
- app/Services/Radio/RadioStreamService.php
- app/Services/Radio/RadioStreamProxy.php
RadioStreamProxy::openStream() opens a web address supplied by the attacker (attacker-controlled URL) without proper checks:
$stream = fopen($url, 'r', false, $conte
Details
Original advisory: https://github.com/advisories/GHSA-6p96-cfg5-4vhp
Referenced CVEs
| CVE | CSIRTS overview | External |
|---|---|---|
| CVE-2026-54493 | coverage & exploitation status | NVD · CVE.org |
More from GitHub Security Advisories
- mediumGHSA-jr6p-8pjj-mfx6: Capsule has an incomplete fix of CVE-2026-22872: TenantResource RawItems and Generators s…2026-07-31
- mediumGHSA-68cj-mvg9-rgm2: Capsule: CapsuleConfiguration NodeMetadata regex fields lack webhook validation, allowing…2026-07-31
- mediumGHSA-ff84-5f28-78qj: re2: Out-of-bounds heap read in `exec`/`test`/`match` via attacker-influenced `lastIndex`…2026-07-31
- mediumGHSA-6hxr-mr5r-9836: re2: Global `String.prototype.match` with an empty-matchable pattern never advances → inf…2026-07-31
- mediumGHSA-x83g-979r-f5fh: Sylius Mollie Plugin has unauthenticated IDOR that leaks order token and customer PII2026-07-31