Jul 15, 2026·5 min read·15 visits
Authenticated Subsonic API users can exploit SSRF vectors in Koel <= 9.6.0 to scan internal networks, loopback interfaces, and cloud metadata resources via unvalidated podcast feed imports and redirect-following stream helpers.
A Server-Side Request Forgery (SSRF) vulnerability in the open-source personal music streaming server Koel allows authenticated Subsonic API users to perform unauthorized network queries. This flaw resides in both the Subsonic podcast feed import routine and the subsequent redirect handling inside the podcast streaming helper, exposing private local networks and internal loopback systems to unauthorized reconnaissance and interaction.
Koel is a personal audio streaming platform that supports a Subsonic-compatible API layer, allowing users to connect external clients. This API introduces a substantial attack surface, including endpoints designated for managing and parsing external podcast XML feeds.
A Server-Side Request Forgery (SSRF) vulnerability, categorized as CWE-918, exists in this functionality. An authenticated user possessing a standard Koel account and an active Subsonic API key can force the Koel application backend to execute HTTP requests to arbitrary systems.
This architecture exposes two distinct attack vectors. The first vector leverages the Subsonic podcast feed import routine, which processes remote feeds before verifying boundary safety. The second vector resides in the streaming helper service, which follows HTTP redirects without validating intermediate hops, allowing attackers to target internal systems or cloud metadata endpoints.
The first SSRF vector resides in the /rest/createPodcastChannel.view Subsonic API endpoint. The underlying request validation class, CreatePodcastChannelRequest.php, relies strictly on standard Laravel URL validation rules. This validation only asserts syntax correctness without restricting requests to loopback addresses, private IP ranges (RFC 1918), or link-local targets.
Once validated, the controller invokes PodcastService::addPodcast(), which initiates external feed parsing via Poddle::fromUrl(). Because the backend queries the target URL to extract the XML structure before checking for network boundaries, an attacker can exploit this endpoint to perform network reconnaissance. The application does validate episode enclosure URLs later during synchronization, but this defense-in-depth mechanism is executed after the initial SSRF vulnerability has already been triggered.
The second vector exists in PodcastService::getStreamableUrl(). While this helper applies a network safety check using Network::isSafeUrl($url) on the initial input, it fetches the resource using Guzzle with redirect following enabled. If an attacker passes an allowed external URL that redirects to a restricted local IP, Guzzle processes the redirect chain silently. The backend then extracts the destination from the Guzzle transfer history without executing a secondary safety check, bypassing the network boundary restrictions.
To resolve the Subsonic validation bypass, the patch integrates a custom SafeUrl validation rule directly into the request validation schema and adds service-layer checks.
// app/Http/Requests/Subsonic/CreatePodcastChannelRequest.php - BEFORE
public function rules(): array
{
return [
'url' => 'required|string|url'
];
}
// app/Http/Requests/Subsonic/CreatePodcastChannelRequest.php - AFTER
use App\Rules\SafeUrl;
public function rules(): array
{
return [
'url' => ['required', 'string', 'url', new SafeUrl()]
];
}Additionally, the service layer was updated to enforce boundary validation directly in the parsing pipeline before network operations occur:
// app/Services/Podcast/PodcastService.php (v9.7.0)
public function createParser(string $url): Parser
{
if (!Network::isSafeUrl($url)) {
throw new UnsafePodcastFeedUrlException($url);
}
return Poddle::fromUrl($url, SafeHttp::client());
}To remediate the redirect-following bypass, Koel replaced raw Guzzle client initializations with a specialized wrapper class named SafeHttp. This wrapper registers an on_redirect middleware callback. This middleware extracts each redirect URL, performs a safety check using Network::isSafeUrl(), and immediately aborts the connection if the target points to a restricted IP address range.
Exploitation requires an authenticated Koel account with access to the Subsonic API key. The attacker can identify this key in their profile settings or via application intercept logs.
In the first scenario, the attacker sets up an internal or external canary designed to log connections, or targets an internal service. The attacker then transmits an HTTP request to the Subsonic podcast creation API endpoint:
GET /rest/createPodcastChannel.view?apiKey=SUBSONIC_API_KEY&f=json&url=http://127.0.0.1:8103/feed.xml HTTP/1.1
Host: koel-target.localUpon receipt, the Koel server resolves the loopback IP and connects to port 8103. If the port is open and returns a valid XML feed, the application logs the registration. If the port is closed or does not host an XML file, the server returns an XML parsing exception. This discrepancy allows the attacker to map active ports and services on the internal network.
For the redirect-based attack, the attacker deploys a public redirection controller. When queried, this controller responds with a redirection header targeting the AWS metadata endpoint:
HTTP/1.1 302 Found
Location: http://169.254.169.254/latest/meta-data/The attacker requests this helper URL through the streaming endpoint, forcing Guzzle to retrieve credentials or metadata from the link-local address and expose the payload to the streaming stream.
The recommended remediation is upgrading the Koel deployment to version 9.7.0 or higher. This release contains patches for both the Subsonic input validation and the HTTP redirect-handling routine.
If upgrading is not immediately possible, apply network-level egress filtering. Configure the host's firewall, such as iptables, to block outbound connections originating from the Koel execution group to RFC 1918 blocks and loopback interfaces:
# Block local and loopback egress for the koel application process
iptables -A OUTPUT -m owner --uid-owner koel -d 127.0.0.0/8 -j REJECT
iptables -A OUTPUT -m owner --uid-owner koel -d 10.0.0.0/8 -j REJECT
iptables -A OUTPUT -m owner --uid-owner koel -d 172.16.0.0/12 -j REJECT
iptables -A OUTPUT -m owner --uid-owner koel -d 192.168.0.0/16 -j REJECT
iptables -A OUTPUT -m owner --uid-owner koel -d 169.254.169.254 -j REJECTAdditionally, implement WAF rules to inspect HTTP parameters. Filter incoming requests targeting /rest/createPodcastChannel.view and block entries where the url parameter contains string representations of private subnets or localhost domains.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
phanan/koel koel | <= 9.6.0 | 9.7.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-918 |
| Attack Vector | Network |
| CVSS | 6.4 |
| Impact | Blind SSRF, Internal Port Scanning, Information Disclosure |
| Exploit Status | PoC |
| KEV Status | Not Listed |
The product takes a user-supplied URL and retrieves it, permitting the application to make requests to unauthorized systems.
A remote code execution vulnerability exists in Microsoft .NET due to untrusted data deserialization within the PresentationCore component. The flaw stems from implicit auto-conversion flags during clipboard data retrieval operations.
An out-of-bounds write vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio allows unauthenticated remote attackers to execute arbitrary code via crafted pixel-shader bytecode or auto-converted clipboard payloads.
ASP.NET Core contains a thread deadlock vulnerability (CWE-833) that allows an unauthenticated remote attacker to cause a denial of service over the network by exhausting server thread pool resources.
CVE-2026-70035 is a high-severity Remote Code Execution (RCE) vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio caused by improper handling during the deserialization of untrusted data (CWE-502). An unauthenticated attacker can execute arbitrary code within the context of the affected process by delivering a crafted serialized payload.
An elevation of privilege vulnerability exists in ASP.NET Core and Microsoft Visual Studio due to improper synchronization during concurrent thread execution. Authenticated remote attackers with low privileges can exploit a timing window to manipulate shared resources and assume higher-level execution contexts.
A path traversal vulnerability (CWE-22) in Contao CMS allows unauthenticated remote attackers to bypass directory boundary restrictions in ImagesController and access files within the project directory.