GHSA-72h5-39r7-r26j AVideo - Incomplete Fix for CVE-2026-27568: Stored XSS via Markdown `javascript:` URI Bypasses ParsedownSafeWithLinks Sanitization
SummaryThe 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.DetailsThe 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:****`ParsedownSafeWithLinks` (lines 349-440)** overrides `blockMarkup()` and `inlineMarkup()` to sanitize raw HTML `<a>` tags via `sanitizeATag()`, which whitelist-checks the URL scheme: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:**`sanitiseElement()` would have called `filterUnsafeUrlInAttribute()` which replaces `:` with `%3A` for non-whitelisted schemes like `javascript:`, but it is never invoked.**Data flow:**User posts comment containing `[Click here](javascript:alert(document.cookie))``xss_esc()` applies `htmlspecialchars()` — no HTML special chars exist in the payload, stored unchangedOn retrieval, `xss_esc_back()` reverses encoding (no-op), then `markDownToHTML()` converts markdown to `<a href="javascript:alert(document.cookie)">Click here</a>`Result stored in `commentWithLinks` (`objects/comment.php:420`)Rendered directly in DOM via template at `view/videoComments_template.php:15`: `<p>{commentWithLinks}</p>`PoCLog in as any user with comment permissionNavigate to any video pagePost a comment with the following markdown:The comment is saved and rendered. Any user viewing the video sees "Click here for more info" as a clickable linkClicking the link executes `alert(document.cookie)` in the victim's browser contextFor session hijacking:Impact**Session hijacking:** Attacker can steal session cookies of any user (including admins) who clicks the comment link, leading to full account takeover**Scope change (S:C):** The XSS executes in the context of the viewing user's session, crossing the trust boundary from the attacker's low-privilege comment context**Persistence:** The payload is stored in the database and triggers for every user who views the page and clicks the link**UI:R required:** The victim must click the link, which limits the severity vs. auto-executing XSSRecommended FixOverride `inlineLink()` in `ParsedownSafeWithLinks` to apply URL scheme filtering to markdown-generated links:Alternatively, re-enable `safeMode(true)` and find a different approach to allow `<a>` and `<img>` tags (e.g., post-processing the safe output to re-inject whitelisted tags).
CVSS v3.1 score: 5.4