GitHub Security Advisory: GHSA-72h5-39r7-r26j
Package: wwbn/avideo (COMPOSER)
Severity: MODERATE (CVSS 5.4)
CWE: CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Vulnerable versions: <= 26.0
Patched in: unpatched

Summary: AVideo - Incomplete Fix for CVE-2026-27568: Stored XSS via Markdown `javascript:` URI Bypasses ParsedownSafeWithLinks Sanitization

Details:
## Summary

The fix for CVE-2026-27568 (GHSA-rcqw-6466-3mv7) introduced a custom `ParsedownSafeWithLinks` class that sanitizes raw HTML `<a>` and `<img>` tags in comments, but explicitly disables Parsedown's `safeMode`. This creates a bypass: markdown link syntax `[text](javascript:alert(1))` is processed by Parsedown's `inlineLink()` method, which does not go through the custom `sanitizeATag()` sanitization (that only handles raw HTML tags). With `safeMode` disabled, Parsedown's built-in `javascript:` URI filtering (`sanitiseElement()`/`filterUnsafeUrlInAttribute()`) is also inactive. An attacker can inject stored XSS via comment markdown links.

## Details

The original fix (commit `ade348ed6`) enabled `setSafeMode(true)`, which activated Parsedown's built-in URL scheme filtering. This was then replaced by commit `f13587c59` with a custom approach that turned safeMode back off:

**`objects/functionsSecurity.php:442-446` — safeMode disabled:**
```php
function markDownToHTML($text) {
    $parsedown = new ParsedownSafeWithLinks();
    $parsedown->setSafeMode(false);   // line 445 — disables Parsedown's built-in javascript: filtering
    $parsedown->setMarkupEscaped(false);
    $html = $parsedown->text($text);
```

**`ParsedownSafeWithLinks` (lines 349-440)** overrides `blockMarkup()` and `inlineMarkup()` to sanitize raw HTML `<a>` tags via `sanitizeATag()`, which whitelist-checks the URL scheme:

```php
// sanitizeATag() at line 360 — only allows http(s), mailto, /, #
if (preg_match('/^(https?:\/\/|mailto:|\/|#)/i', $url)) {
    $href = ' href="' . htmlspecialchars($url, ENT_QUOTES) . '"';
}
```

However, this sanitization only runs for **raw HTML** `<a>` tags processed through `inlineMarkup()`. Markdown-syntax links (`[text](url)`) are handled by Parsedown's core `inlineLink()` method (`vendor/erusev/parsedown/Parsedown.php:1258`), which constructs an element array and passes it to `element()`.

**`vendor/erusev/parsedown/Parsedown.php:1470-1475` — sanitiseElement only runs when safeMode is true:**
```php
protected function element(array $Element)
{
    if ($this->safeMode)        // false — so sanitiseElement() is never called
    {
        $Element = $this->sanitiseElement($Element);
    }
```

`sanitiseElement()` would have called `filterUnsafeUrlInAttribute()` which replaces `:` with `%3A` for non-whitelisted schemes like `javascript:`, but it is never invoked.

**Data flow:**
1. User posts comment containing `[Click here](javascript:alert(document.cookie))`
2. `xss_esc()` applies `htmlspecialchars()` — no HTML special chars exist in the payload, stored unchanged
3. On retrieval, `xss_esc_back()` reverses encoding (no-op), then `markDownToHTML()` converts markdown to `<a href="javascript:alert(document.cookie)">Click here</a>`
4. Result stored in `commentWithLinks` (`objects/comment.php:420`)
5. Rendered directly in DOM via template at `view/videoComments_template.php:15`: `<p>{commentWithLinks}</p>`

## PoC

1. Log in as any user with commen