GitHub Security Advisory: GHSA-ff5q-cc22-fgp4
Package: wwbn/avideo (COMPOSER)
Severity: HIGH (CVSS 7.1)
CWE: CWE-346: Origin Validation Error
Vulnerable versions: <= 29.0
Patched in: unpatched

Summary: WWBN AVideo has a CORS Origin Reflection Bypass via plugin/API/router.php and allowOrigin(true) Exposes Authenticated API Responses

Details:
## Summary

The CORS origin validation fix in commit `986e64aad` is incomplete. Two separate code paths still reflect arbitrary `Origin` headers with credentials allowed for all `/api/*` endpoints: (1) `plugin/API/router.php` lines 4-8 unconditionally reflect any origin before application code runs, and (2) `allowOrigin(true)` called by `get.json.php` and `set.json.php` reflects any origin with `Access-Control-Allow-Credentials: true`. An attacker can make cross-origin credentialed requests to any API endpoint and read authenticated responses containing user PII, email, admin status, and session-sensitive data.

## Details

### Bypass Vector 1: router.php independent CORS handler

`plugin/API/router.php:4-8` runs before any application code:

```php
// plugin/API/router.php lines 4-8
$HTTP_ORIGIN = empty($_SERVER['HTTP_ORIGIN']) ? @$_SERVER['HTTP_REFERER'] : $_SERVER['HTTP_ORIGIN'];
if (empty($HTTP_ORIGIN)) {
    header('Access-Control-Allow-Origin: *');
} else {
    header("Access-Control-Allow-Origin: " . $HTTP_ORIGIN);
}
```

This reflects **any** `Origin` header verbatim. For OPTIONS preflight requests (lines 14-18), the script exits immediately — the fixed `allowOrigin()` function never executes:

```php
// plugin/API/router.php lines 14-18
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    header("Access-Control-Max-Age: 86400");
    http_response_code(200);
    exit;
}
```

All `/api/*` requests are routed through this file via `.htaccess` rules (lines 131-132).

### Bypass Vector 2: allowOrigin($allowAll=true)

Both `plugin/API/get.json.php:12` and `plugin/API/set.json.php:12` call `allowOrigin(true)`. In `objects/functions.php:2773-2790`, the `$allowAll=true` code path reflects any origin with credentials:

```php
// objects/functions.php lines 2773-2777
if ($allowAll) {
    $requestOrigin = $_SERVER['HTTP_ORIGIN'] ?? '';
    if (!empty($requestOrigin)) {
        header('Access-Control-Allow-Origin: ' . $requestOrigin);
        header('Access-Control-Allow-Credentials: true');
    }
```

This code path was **untouched** by commit `986e64aad`, which only hardened the default (`$allowAll=false`) path.

### Impact on data exposure

Because the victim's session cookies are sent with credentialed cross-origin requests, `User::isLogged()` returns true and `User::getId()` returns the victim's user ID. This means:

- **Video listing endpoint** (`get_api_video`): Sensitive user fields (email, isAdmin, etc.) are only stripped for unauthenticated requests (`functions.php:1752`), so authenticated CORS requests receive the full data.
- **User profile endpoint** (`get_api_user`): When `$isViewingOwnProfile` is true (line 3039), all sensitive fields including email, admin status, recovery tokens, and PII are returned unstripped.

### Additional issue: Referer header fallback

`router.php` line 4 falls back to `HTTP_REFERER` when `HTTP_ORIGIN` is absent, injecting an attacker-controlled full URL (not just origin) into the `Access-Control-Allow-Origin`