GHSA-ccq9-r5cw-5hwq WWBN AVideo has CORS Origin Reflection with Credentials on Sensitive API Endpoints Enables Cross-Origin Account Takeover
SummaryThe `allowOrigin($allowAll=true)` function in `objects/functions.php` reflects any arbitrary `Origin` header back in `Access-Control-Allow-Origin` along with `Access-Control-Allow-Credentials: true`. This function is called by both `plugin/API/get.json.php` and `plugin/API/set.json.php` — the primary API endpoints that handle user data retrieval, authentication, livestream credentials, and state-changing operations. Combined with the application's `SameSite=None` session cookie policy, any website can make credentialed cross-origin requests and read authenticated API responses, enabling theft of user PII, livestream keys, and performing state changes on behalf of the victim.DetailsThe vulnerable code path is in `objects/functions.php` lines 2773-2791:This is called unconditionally at the top of both API entry points:The comment above the code claims "These endpoints return public ad XML and carry no session-sensitive data" — this is incorrect. The same `allowOrigin(true)` call gates the entire API surface.The attack is enabled by the session cookie configuration at `objects/include_config.php:144`:This ensures the browser sends the victim's session cookie on cross-origin requests, which the API then uses for authentication via `$_SESSION['user']['id']` (in `User::getId()`).When a logged-in user's session is present, the `get_api_user` endpoint (API.php:3009) returns full user data without sanitization for the user's own profile (`$isViewingOwnProfile = true` bypasses `removeSensitiveUserFields`), including:Email, full name, address, phone, birth date (PII)Admin status and permission flagsLivestream server URL with embedded password (API.php:3059)Encrypted stream key (API.php:3063)The recent fix in commit `986e64aad` addressed CORS handling in the non-`$allowAll` path (null origin and trusted subdomains) but left this far more dangerous `$allowAll=true` path completely untouched.PoC**Step 1:** Host the following HTML on any domain (e.g., `https://attacker.example`):**Step 2:** Victim visits the attacker page while logged into the AVideo instance.**Step 3:** The browser sends a credentialed cross-origin GET request to the API. The server responds with:**Step 4:** The attacker's JavaScript reads the full authenticated API response containing the victim's email, name, address, phone, admin status, livestream credentials, and stream keys.**Step 5 (optional escalation):** The attacker can also invoke `set.json.php` endpoints to perform state changes on behalf of the victim.Impact**User PII theft**: Email, full name, address, phone number, birth date of any logged-in user who visits an attacker-controlled page**Account compromise**: Livestream server credentials (including password) and stream keys are exposed, allowing stream hijacking**Admin reconnaissance**: Admin status and all permission flags are exposed, enabling targeted attacks on privileged accounts**State modification**: The `set.json.php` endpoint is equally affected, allowing attackers to perform write operations (video management, settings changes) on behalf of the victim**Mass exploitation**: No per-user targeting required — a single attacker page can harvest data from every logged-in visitorRecommended FixReplace the permissive origin reflection in `allowOrigin()` with validation against the site's configured domain. The `$allowAll` path should validate the origin the same way the non-`$allowAll` path does:Additionally, consider separating the truly public endpoints (VAST/VMAP ad XML) from the sensitive API endpoints so they can have different CORS policies, rather than sharing one permissive `allowOrigin(true)` call.
CVSS v3.1 score: 8.1