GitHub Security Advisory: GHSA-ffw8-fwxp-h64w
Package: wwbn/avideo (COMPOSER)
Severity: HIGH (CVSS 7.1)
CWE: CWE-352: Cross-Site Request Forgery (CSRF)
Vulnerable versions: <= 29.0
Patched in: unpatched

Summary: WWBN AVideo has Multiple CSRF Vulnerabilities in Admin JSON Endpoints (Category CRUD, Plugin Update Script)

Details:
## Summary

Three admin-only JSON endpoints — `objects/categoryAddNew.json.php`, `objects/categoryDelete.json.php`, and `objects/pluginRunUpdateScript.json.php` — enforce only a role check (`Category::canCreateCategory()` / `User::isAdmin()`) and perform state-changing actions against the database without calling `isGlobalTokenValid()` or `forbidIfIsUntrustedRequest()`. Peer endpoints in the same directory (`pluginSwitch.json.php`, `pluginRunDatabaseScript.json.php`) do enforce the CSRF token, so the missing checks are an omission rather than a design choice. An attacker who lures a logged-in admin to a malicious page can create, update, or delete categories and force execution of any installed plugin's `updateScript()` method in the admin's session.

## Details

AVideo's CSRF defense is not applied globally — each endpoint must explicitly call `isGlobalTokenValid()` (defined in `objects/functions.php:2313`), which verifies `$_REQUEST['globalToken']`. A search across the codebase shows 18 files that correctly invoke `forbidIfIsUntrustedRequest()` or `isGlobalTokenValid()`, while the three endpoints below do not.

### 1. `objects/categoryAddNew.json.php:18` — CSRF create/overwrite category

```php
 18 if (!Category::canCreateCategory()) {
 19     $obj->msg = __("Permission denied");
 20     die(json_encode($obj));
 21 }
 22
 23 $objCat = new Category(intval(@$_POST['id']));
 24 $objCat->setName($_POST['name']);
 25 $objCat->setClean_name($_POST['clean_name']);
 26 $objCat->setDescription($_POST['description']);
 27 $objCat->setIconClass($_POST['iconClass']);
 28 $objCat->setSuggested($_POST['suggested']);
 29 $objCat->setParentId($_POST['parentId']);
 30 $objCat->setPrivate($_POST['private']);
 31 $objCat->setAllow_download($_POST['allow_download']);
 32 $objCat->setOrder($_POST['order']);
 33 $obj->categories_id = $objCat->save();
```

`Category::canCreateCategory()` (`objects/category.php:620-630`) returns true for any admin. Because the row is loaded via `new Category(intval(@$_POST['id']))`, a non-zero `id` causes the existing row to be overwritten, not just created — the same primitive can mutate existing categories. No CSRF/Origin check precedes the write.

### 2. `objects/categoryDelete.json.php:10` — CSRF delete category

```php
 10 if (!Category::canCreateCategory()) {
 11     die('{"error":"' . __("Permission denied") . '"}');
 12 }
 13 require_once 'category.php';
 14 $obj = new Category($_POST['id']);
 15 $response = $obj->delete();
```

No token check. An attacker can force an admin browser to POST any `id`, deleting rows from `categories`.

### 3. `objects/pluginRunUpdateScript.json.php:9` — CSRF forced plugin update

```php
  9 if (!User::isAdmin()) {
 10     forbiddenPage('Permission denied');
 11 }
 12 if (empty($_POST['name'])) {
 13     forbiddenPage('Name can\'t be blank');
 14 }
 15 ini_set('max_execution_time', 300);
 16 require_once $global['systemRootPath'] . 'plugin/AVideoPlugin.php';
 17
 18 if($_POST['uuid'] == 'plist123