CVE-2026-59923 Overview
CVE-2026-59923 is a Cross-Site Scripting (XSS) vulnerability in Mistune, a widely used Python Markdown parser with pluggable renderers. Versions prior to 3.3.0 contain a flaw in the HTMLRenderer.safe_url() method that fails to block percent-encoded javascript: URIs. Attacker-supplied Markdown links or images can bypass URL sanitization and execute script in the rendered HTML output. Any application that renders untrusted Markdown to HTML using Mistune is affected, including documentation platforms, note-taking tools, and content management systems. The issue is tracked as [CWE-79] and was fixed in Mistune 3.3.0.
Critical Impact
Attackers can execute arbitrary JavaScript in a victim's browser session by submitting crafted Markdown, leading to session theft, credential harvesting, or unauthorized actions on behalf of the user.
Affected Products
- Mistune Python Markdown parser, all versions prior to 3.3.0
- Applications embedding Mistune for user-generated Markdown rendering
- Documentation and wiki platforms using HTMLRenderer with default URL sanitization
Discovery Timeline
- 2026-07-08 - CVE-2026-59923 published to NVD
- 2026-07-08 - Last updated in NVD database
- Fix released - Mistune 3.3.0 published on GitHub with patched safe_url() logic
Technical Details for CVE-2026-59923
Vulnerability Analysis
Mistune's HTMLRenderer.safe_url() method inspects link and image URLs to block dangerous schemes such as javascript:, vbscript:, and data:. The check operates on the raw URL string without first decoding percent-encoded characters. An attacker can percent-encode part of the scheme, for example java%73cript:alert(1) where %73 decodes to s, and the sanitizer treats the string as safe. When the browser later parses the emitted href attribute, it decodes the URL and executes the JavaScript scheme.
The weakness maps to [CWE-79] Improper Neutralization of Input During Web Page Generation. Exploitation requires user interaction, typically clicking a rendered link, and produces a scope-changing impact because injected script runs in the origin of the hosting application.
Root Cause
The root cause is missing URL decoding prior to scheme validation. The sanitizer performs a case-insensitive prefix match against a denylist of dangerous schemes but never calls urllib.parse.unquote() on the input. Any encoding of the scheme characters slips past the check.
Attack Vector
An attacker submits Markdown such as [click me](java%73cript:alert(document.cookie)) or an image reference with an encoded javascript: URI. The application renders the Markdown to HTML using Mistune's HTMLRenderer, producing an anchor whose href retains the encoded payload. When a victim clicks the link, the browser decodes the URI and executes the script in the application's origin.
# Patch: src/mistune/renderers/html.py
# fix(renderer): block encoded unsafe URL schemes
from typing import Any, ClassVar, Dict, Optional, Tuple, Literal
+from urllib.parse import unquote
from ..core import BaseRenderer, BlockState
from ..util import escape as escape_text
from ..util import safe_entity, striptags
# Source: https://github.com/lepture/mistune/commit/c7101fcbb6e8790e8e39157c5ca2238fc6dd6cbc
The patch introduces unquote from urllib.parse so that safe_url() normalizes the URL before comparing its scheme against the denylist.
Detection Methods for CVE-2026-59923
Indicators of Compromise
- Rendered HTML pages containing anchor tags with href values matching java%[0-9a-f]{2}cript: or similar percent-encoded scheme patterns
- Application logs recording Markdown submissions that include %3A (encoded colon) adjacent to scheme-like prefixes
- Browser Content Security Policy (CSP) violation reports referencing inline script execution triggered from Markdown-rendered pages
Detection Strategies
- Scan stored Markdown content and rendered HTML for percent-encoded scheme fragments such as %73, %63, or %3A inside href and src attributes
- Add regex-based Web Application Firewall (WAF) rules that inspect POST bodies for encoded javascript variants in user-submitted Markdown
- Perform runtime checks on outbound HTML by decoding URL attributes and re-validating scheme against a strict allowlist
Monitoring Recommendations
- Instrument the Markdown rendering pipeline to log any URL where the decoded scheme differs from the raw scheme
- Enable CSP with script-src restrictions and forward violation reports to a central logging system for review
- Track the installed Mistune version across services and alert on any deployment still running a release earlier than 3.3.0
How to Mitigate CVE-2026-59923
Immediate Actions Required
- Upgrade Mistune to version 3.3.0 or later in all applications that render untrusted Markdown
- Audit dependency manifests such as requirements.txt, pyproject.toml, and Pipfile.lock to confirm no transitive installs pin an earlier version
- Purge or re-render cached HTML output produced by vulnerable Mistune versions to remove any stored malicious links
Patch Information
The fix is available in Mistune 3.3.0. The corrective change is documented in the upstream commit c7101fc and the GitHub Security Advisory GHSA-8c25-4j27-2rv3. Install with pip install --upgrade mistune>=3.3.0.
Workarounds
- Subclass HTMLRenderer and override safe_url() to call urllib.parse.unquote() on the URL before validating its scheme
- Post-process rendered HTML through an HTML sanitizer such as bleach configured with a strict URL scheme allowlist (http, https, mailto)
- Deploy a strong Content Security Policy that blocks inline script execution and disallows javascript: navigation
# Upgrade Mistune to the patched release
pip install --upgrade 'mistune>=3.3.0'
# Verify the installed version
python -c "import mistune; print(mistune.__version__)"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

