GHSA-ghx5-7jjg-q2j7: AVideo vulnerable to Stored XSS via html_entity_decode() Reversing xss_esc() Sanitization in Channel About Field
SummaryA sanitization order-of-operations flaw in the user profile "about" field allows any registered user to inject arbitrary JavaScript that executes when other users visit their channel page. The `xss_esc()` function entity-encodes input before `strip_specific_tags()` can match dangerous HTML tags, and `html_entity_decode()` on output reverses the encoding, restoring the raw malicious HTML.Details**Input sanitization** in `objects/user.php:156`:The call order is `strip_specific_tags(xss_esc($about))`. The inner `xss_esc()` function (`objects/functionsSecurity.php:233`) calls `htmlspecialchars()`:This encodes `<script>alert(1)</script>` to `&lt;script&gt;alert(1)&lt;/script&gt;`.Then `strip_specific_tags()` (`objects/functions.php:6623-6636`) runs regex patterns to remove dangerous tags:But the regex looks for literal `<script>` — it can never match the entity-encoded `&lt;script&gt;`. The sanitizer is completely neutralized by the encoding that precedes it.**Output** in `view/channelBody.php:239-246`:The `html_entity_decode()` call reverses the `htmlspecialchars()` encoding, restoring the original raw HTML including `<script>` tags. The result is echoed directly into the page without any further escaping.**Secondary vector:** The `<img>` tag is not in the `strip_specific_tags` blocklist (`['script', 'style', 'iframe', 'object', 'applet', 'link']`), so payloads like `<img src=x onerror=...>` bypass even the intended tag stripping entirely.The about field is set via `objects/userUpdate.json.php:28`, accessible to any logged-in user:The channel page (`view/channelBody.php`) is publicly accessible — no authentication is required to view it.PoC**Step 1:** Log in as any registered user and update the "about" field:**Step 2:** Any user (including unauthenticated visitors) navigates to the attacker's channel page:**Expected result:** The JavaScript in the `onerror` handler executes in the visitor's browser, displaying their session cookie.**Alternative payload using `<script>` tag (also works due to the sanitization bypass):**Impact**Session hijacking:** Attacker can steal session cookies of any user (including administrators) who visits their channel page**Account takeover:** Stolen admin session tokens allow full administrative access to the AVideo instance**Phishing:** Attacker can inject fake login forms or redirect users to malicious sites**Worm potential:** Stored XSS could modify other users' profiles programmatically, creating a self-propagating wormThis is a stored XSS affecting all visitors to any attacker-controlled channel page, with no user interaction beyond navigating to the page.Recommended Fix**Option 1 (Recommended — remove html_entity_decode):** The entity-encoded string is already safe for display. Remove the decode call in `view/channelBody.php`:**Option 2 (If rich HTML is intended):** Reverse the sanitization order in `objects/user.php:156` and use a proper sanitizer:**Option 3 (Best — if rich HTML in about is desired):** Replace both `strip_specific_tags()` and `xss_esc()` with HTMLPurifier, which properly handles allowlisted HTML sanitization:And on output, remove `html_entity_decode()` — output the purified HTML directly.
CVSS v3.1: 5.4