CVE-2026-59923: Mistune Percent-Encoded JavaScript URI Bypass in HTML Rendering
Mistune, a widely-used Python library for converting Markdown to HTML, contains a flaw in how it validates links and image URLs. An attacker can craft Markdown that includes specially encoded JavaScript commands disguised in percent-encoded format. When a user renders this malicious Markdown through Mistune versions before 3.3.0, the library fails to block these hidden scripts, allowing them to execute in the browser. This affects any application that accepts user-supplied Markdown and displays the rendered output to other users.
Source data · NVD / CISA · public domain
- CVSS
- 3.1 · 6.1 MEDIUM · CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
- Weaknesses (CWE)
- CWE-79
- Affected products
- 1 configuration(s)
- Published / Modified
- 2026-07-08 / 2026-07-09
NVD description (verbatim)
Mistune is a Python Markdown parser with renderers and plugins. Prior to 3.3.0, HTMLRenderer.safe_url() does not block percent-encoded javascript URIs, allowing attacker-supplied Markdown links or images to bypass URL protections and execute script in rendered HTML. This issue is fixed in version 3.3.0.
4 reference(s) · View on NVD →
SEC.co analysis · AI-assisted, reviewed against source
Technical summary
The vulnerability exists in HTMLRenderer.safe_url(), a sanitization function designed to prevent JavaScript execution through data URIs and similar attack vectors. The function does not properly decode or validate percent-encoded characters before checking against its URL blocklist. An attacker can bypass protections by submitting Markdown links with payloads like [click me](javascript%3Aalert(1)), where %3A represents a colon. The renderer processes this through HTML generation without detecting the JavaScript URI, resulting in XSS. The issue stems from incomplete URL validation logic rather than a fundamental design flaw, and is resolved in version 3.3.0 by implementing stricter decoding and validation before safe_url() evaluation.
Business impact
Applications embedding Mistune for user-generated content rendering—such as documentation platforms, comment systems, wiki-style tools, or collaborative editing features—face cross-site scripting (XSS) exposure. A successful exploit allows attackers to steal session tokens, deface content, perform actions on behalf of users, or redirect victims to malicious sites. The risk is elevated in multi-tenant environments or open platforms where untrusted users can submit Markdown. Organizations relying on Mistune for any security-sensitive rendering should treat this as a priority update, particularly if the rendered output is visible to other users or involves sensitive data.
Affected systems
Mistune versions prior to 3.3.0 are affected. This includes all 2.x releases and 3.0.x through 3.2.x. Organizations should inventory their Python environments and dependency manifests for mistune imports, including transitive dependencies. Web applications, static site generators, documentation tools, and any service using Mistune for Markdown processing should be scanned. The vulnerability does not affect users running Mistune 3.3.0 or later.
Exploitability
The vulnerability requires user interaction—a victim must visit a page or application where attacker-controlled Markdown is rendered. No authentication or special network access is required. The attack surface is large if the application accepts Markdown from untrusted sources (forums, comments, user profiles, uploaded documents). The percent-encoding bypass is straightforward to craft, requiring no sophisticated tooling. However, exploitation depends on the rendering context: if output is sanitized by a downstream HTML filter or Content Security Policy, impact may be mitigated. CVSS 3.1 score of 6.1 (MEDIUM) reflects network-based delivery, low attack complexity, and low privileges needed, but notes that user interaction and limited scope (only the victim's browser session) cap severity.
Remediation
Upgrade Mistune to version 3.3.0 or later immediately. Review your application's dependency tree to confirm the version in use and check for transitive dependencies on older Mistune releases. If an immediate upgrade is not feasible, consider implementing an additional HTML sanitization layer (such as bleach or DOMPurify) downstream of Mistune rendering as a temporary compensating control, though this is not a substitute for the fix. Test rendering of user-supplied Markdown after patching to ensure no regressions in legitimate URL handling.
Patch guidance
Version 3.3.0 is the fixed release. Obtain it from the official Mistune repository or PyPI. Verify compatibility with your application's Python version and other dependencies before deploying to production. The fix involves improved URL decoding and validation logic in HTMLRenderer.safe_url(); review the changelog or commit history to understand the specific changes. If your project pins Mistune to an older version, update the constraint in your requirements.txt, Pipfile, or pyproject.toml and run dependency resolution tests. Deploy to development and staging environments first, particularly if your application heavily customizes or extends Mistune rendering.
Detection guidance
Search code repositories and dependency manifests for mistune imports and check installed versions using pip show mistune or by parsing requirements files and lock files. Monitor runtime logs for unusual Markdown submissions containing percent-encoded characters (look for %3A, %2F, %2B patterns in link or image src attributes). Implement application-level logging of Markdown inputs and rendered HTML outputs to audit for suspicious patterns. Use dependency scanning tools (Snyk, Dependabot, Safety) to flag Mistune versions <3.3.0 automatically. Review any stored Markdown or cached HTML for malicious payloads if you suspect prior exploitation. Security scanning of published static sites or cached documentation may reveal injected scripts if they were rendered and published before patching.
Why prioritize this
Although CVSS is MEDIUM (6.1), this vulnerability merits prompt attention due to the ease of exploitation and prevalence of Mistune in Python web ecosystems. The percent-encoding bypass is trivial to execute, and the impact is direct XSS in user-facing content. Any organization with user-generated Markdown content or documentation pipelines should prioritize this fix. The fix is not disruptive—upgrading to 3.3.0 is a straightforward dependency bump without API changes—making delay unjustifiable.
Risk score, explained
CVSS 3.1 assigns 6.1 (MEDIUM) based on: Attack Vector Network (exploitable remotely), Attack Complexity Low (percent-encoding bypass is simple), Privileges Required None (no auth needed), User Interaction Required (victim must view the malicious content), Scope Changed (XSS can affect other users or systems via the victim's session), Confidentiality Impact Low (session data theft possible), Integrity Impact Low (content modification possible), Availability Impact None (no DoS). The score appropriately reflects the conditional nature of XSS (user interaction) while acknowledging the practical ease of crafting and delivering the payload.
Frequently asked questions
Does this vulnerability affect Mistune users who only render trusted, internal Markdown?
No, risk is minimal if all Markdown sources are controlled by your organization and vetted before processing. The vulnerability requires attacker-supplied Markdown to be exploited. If Mistune is used solely for internal documentation or static content authored by your team, update at your normal patch cycle. However, if there is any possibility of external or user-contributed input, prioritize the patch.
Can I use Content Security Policy (CSP) or other browser protections to mitigate this risk without upgrading?
Possibly, but it is not reliable. A restrictive CSP (e.g., script-src 'none') can block inline or dynamically injected scripts, providing defense-in-depth. However, percent-encoded JavaScript URIs in links may still allow data exfiltration or navigation attacks. Downstream HTML sanitization (bleach library) can also reduce risk, but these are compensating controls, not a substitute for the patch. Upgrade Mistune to 3.3.0 to eliminate the root cause.
Is there a workaround if upgrading is not immediately possible?
As a temporary measure, pipe all Mistune output through an HTML sanitizer such as bleach configured to strip dangerous attributes and event handlers. Additionally, enforce a strict Content Security Policy on all pages rendering Mistune content. Monitor for suspicious submissions and review logs for percent-encoded characters in Markdown. These steps reduce risk but do not eliminate it—plan an upgrade to 3.3.0 as soon as feasible.
How do I know if my application is vulnerable?
Check your installed Mistune version (pip show mistune or grep requirements.txt). If it is 3.2.x or earlier, you are vulnerable. If your application accepts Markdown from any untrusted source (users, uploaded files, APIs), the risk is high. Test by submitting a harmless percent-encoded JavaScript link (e.g., [test](javascript%3Aalert('xss'))) to your Markdown renderer and inspecting the HTML output; if the script executes or the href contains decoded JavaScript, you are affected.
This analysis is provided for informational purposes and is based on official CVE data and vendor advisories current as of the date of publication. While we strive for accuracy, organizations should verify all patch versions, compatibility information, and remediation steps against official Mistune releases and their own environment documentation. Security assessments are contextual; consult with your development and security teams to determine appropriate prioritization for your specific infrastructure. SEC.co assumes no liability for decisions made based on this intelligence. Always test patches in non-production environments before deployment. Source: NVD (public-domain), retrieved 2026-08-17. Analysis generated by SEC.co (claude-haiku-4-5).
Related vulnerabilities
- CVE-2026-59926MEDIUMMistune Markdown Parser XSS via Attribute Injection
- CVE-2026-59929MEDIUMMistune URL Scheme Bypass Vulnerability – XSS Risk in Markdown Parser
- CVE-2016-20070MEDIUMPrivilege Escalation & Stored XSS in WordPress Booking Calendar Contact Form 1.0.23
- CVE-2018-25384MEDIUMStored XSS in Wikidforum 2.20 Allows Authenticated Attackers to Inject Malicious Scripts
- CVE-2019-25731MEDIUMStored XSS in Zuz Music 2.1 Contact Form
- CVE-2019-25737MEDIUMStored XSS in Live Chat Unlimited 2.8.3 – Admin Session Compromise
- CVE-2019-25739MEDIUMGigToDo 1.3 Stored XSS Vulnerability in Proposal Descriptions
- CVE-2019-25742MEDIUMStored XSS in Zoner Real Estate WordPress Theme 4.1.1 – Admin Account Compromise Risk