GHSA-hv36-p4w4-6vmj AVideo Affected by CSRF on Plugin Import Endpoint Enables Unauthenticated Remote Code Execution via Malicious Plugin Upload
SummaryThe `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.DetailsThe root cause has two components working together:**1. SameSite=None on session cookies (`objects/include_config.php:134-137`):**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`):**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 validationNo 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****Step 2: Host the CSRF exploit page****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**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):**2. Update the upload form in `view/managerPluginUpload.php`** to include the token:And pass it in the JavaScript upload config:**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.
CVSS v3.1 score: 8.8