CVE-2026-5389 Overview
CVE-2026-5389 is a cross-site scripting (XSS) vulnerability in the justhtml Python library, affecting versions before 1.13.0. The flaw resides in the to_markdown() function when it serializes attacker-controlled <pre> content. Attackers can inject backticks inside sanitized <pre> elements to break out of fixed-length Markdown code fences. When the resulting Markdown is rendered by CommonMark or GitHub Flavored Markdown (GFM) parsers, injected raw HTML executes in the victim's browser. The weakness is classified under CWE-80: Improper Neutralization of Script-Related HTML Tags in a Web Page.
Critical Impact
Successful exploitation allows attackers to execute arbitrary HTML and JavaScript in the context of any application that renders justhtml-generated Markdown, enabling session theft and account takeover.
Affected Products
- justhtml versions prior to 1.13.0
- Applications using justhtml.to_markdown() to serialize untrusted HTML
- Downstream renderers processing the output with CommonMark or GFM parsers
Discovery Timeline
- 2026-08-23 - CVE-2026-5389 published to the National Vulnerability Database (NVD)
- 2026-08-26 - Last updated in NVD database
Technical Details for CVE-2026-5389
Vulnerability Analysis
The justhtml library converts HTML fragments into Markdown using the to_markdown() function. When it encounters a <pre> element, it wraps the sanitized inner content within a Markdown code fence composed of a fixed number of backtick characters. The sanitizer preserves backticks inside <pre> blocks because they are considered safe within a preformatted context.
CommonMark and GFM define code fences as a run of at least three backticks, and content inside a fence terminates when an equal or longer run of backticks appears on its own line. Because justhtml uses a fixed fence length, an attacker who submits HTML containing a backtick run equal to or longer than the generated fence causes the fence to close prematurely. Content following the injected fence terminator is then interpreted as regular Markdown, which permits raw HTML in CommonMark and GFM. This turns previously benign <pre> content into an XSS sink whenever the output is rendered client-side.
Root Cause
The root cause is a mismatch between the sanitizer's fence-length assumption and the Markdown parser's fence-termination rules. justhtml selects a static number of backticks for the opening and closing fence without measuring the longest backtick run in the sanitized content. This violates the CommonMark specification's requirement that a fence enclosing arbitrary content must be strictly longer than any internal backtick sequence.
Attack Vector
Exploitation requires user interaction, since a victim must render Markdown produced from attacker-supplied HTML. An attacker submits HTML containing a <pre> element whose inner text includes a run of backticks matching or exceeding the fence length used by to_markdown(). After the sanitizer emits Markdown, the injected backticks close the fence and any trailing raw HTML, such as <img onerror=...> or <script> payloads permitted by the downstream renderer, executes in the browser. See the GitHub Security Advisory GHSA-5vp3-3cg6-2rq3 and the VulnCheck Advisory for technical details.
// No verified proof-of-concept code is published for CVE-2026-5389.
// Refer to the linked GitHub Security Advisory for reproduction details.
Detection Methods for CVE-2026-5389
Indicators of Compromise
- User-submitted HTML containing <pre> elements with unusually long runs of backtick characters (three or more consecutive backticks).
- Rendered pages showing HTML tags such as <img>, <iframe>, or <script> originating from Markdown fields fed by justhtml.to_markdown().
- Outbound requests to attacker-controlled domains from browsers viewing Markdown-rendered content generated by vulnerable justhtml versions.
Detection Strategies
- Inventory Python dependencies and flag any project pinning justhtml at a version below 1.13.0.
- Add a linter or static-analysis rule that inspects Markdown output for backtick runs equal to or longer than the fence emitted by the sanitizer.
- Instrument web application firewalls (WAFs) to alert on POST bodies containing <pre> blocks with three or more consecutive backticks combined with HTML tag syntax.
Monitoring Recommendations
- Log the raw Markdown produced by to_markdown() and scan it for orphan fence terminators before rendering.
- Monitor Content Security Policy (CSP) violation reports for inline-script and inline-event handler blocks on pages that render user-generated Markdown.
- Track anomalous session activity, such as unexpected cookie access or token exfiltration attempts, following interactions with Markdown-rendered content.
How to Mitigate CVE-2026-5389
Immediate Actions Required
- Upgrade justhtml to version 1.13.0 or later across all environments that call to_markdown().
- Audit application code paths that convert untrusted HTML into Markdown and reject inputs containing backtick runs above a documented threshold until the upgrade is deployed.
- Rotate session tokens and API credentials that may have been exposed on pages rendering attacker-controlled Markdown.
Patch Information
The maintainer released a fix in justhtml1.13.0. The patch adjusts fence generation so the opening and closing fences are always longer than the longest backtick run present in the sanitized <pre> content, aligning behavior with the CommonMark specification. Refer to the GitHub Security Advisory GHSA-5vp3-3cg6-2rq3 for the fixed release notes.
Workarounds
- Post-process to_markdown() output through a Markdown renderer configured to disable raw HTML, such as CommonMark with the safe option enabled.
- Apply a strict Content Security Policy (CSP) that blocks inline scripts and inline event handlers on pages rendering user-generated Markdown.
- Pre-filter submitted HTML to strip or escape backtick sequences of three or more characters inside <pre> elements before invoking justhtml.
# Upgrade justhtml to the patched release
pip install --upgrade 'justhtml>=1.13.0'
# Verify the installed version
python -c "import justhtml; print(justhtml.__version__)"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

