GitHub Advisoryadvisory · Packagist
GHSA-72h5-39r7-r26j AVideo - Incomplete Fix for CVE-2026-27568: Stored XSS via Markdown `javascript:` URI Bypasses ParsedownSafeWithLinks Sanitization
MEDIUM
Official page ↗
- Aliases
- CVE-2026-33500
- Ecosystem
- Packagist
- Packages
- wwbn/avideo
- Severity
- Moderate
- CVSS vector
- CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N
- Weaknesses
- CWE-79
- Reviewed
- 2026-03-20
Affected packages
• Packagist wwbn/avideo: <= 26.0 (no fix yet)
Description
Summary
The fix for CVE-2026-27568 (GHSA-rcqw-6466-3mv7) introduced a custom `ParsedownSafeWithLinks` class that sanitizes raw HTML `` and `` tags in comments, but explicitly disables Parsedown's `safeMode`. This creates a bypass: markdown link syntax `text)` 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 `` 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 `` tags processed through `inlineMarkup()`. Markdown-syntax links (`text`) 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)`
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 `Click here`
4. Result stored in `commentWithLinks` (`objects/comment.php:420`)
5. Rendered directly in DOM via template at `view/videoComments_template.php:15`: `{commentWithLinks}`
PoC
1. Log in as any user with comment permission
2. Navigate to any video page
3. Post a comment with the following markdown:
```
Click here for more info)
```
4. The comment is saved and rendered. Any user viewing the video sees "Click here for more info" as a clickable link
5. Clicking the link executes `alert(document.cookie)` in the victim's browser context
For session hijacking:
```
See related video)
```
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 XSS
Recommended Fix
Override `inlineLink()` in `ParsedownSafeWithLinks` to apply URL scheme filtering to markdown-generated links:
```php
class ParsedownSafeWithLinks extends Parsedown
{
// ... existing code ...
protected function inlineLink($Excerpt)
{
$Link = parent::inlineLink($Excerpt);
if ($Link === null) {
return null;
}
$href = $Link['element']['attributes']['href'] ?? '';
// Apply the same whitelist as sanitizeATag: only allow http(s), mailto, relative, anchors
if ($href !== '' && !preg_match('/^(https?:\/\/|mailto:|\/|#)/i', $href)) {
$Link['element']['attributes']['href'] = '';
}
return $Link;
}
}
```
Alternatively, re-enable `safeMode(true)` and find a different approach to allow `` and `` tags (e.g., post-processing the safe output to re-inject whitelisted tags).
Related
Alias · CVE (1)
- CVE-2026-33500 WWBN AVideo is an open source video platform. vulnerability
Weakness · CWE (1)
- CWE-79 Improper Neutralization of Input During Web Page Generation weakness