CSIRTS // UNIFIED SECURITY ADVISORY FEEDSYS ● ONLINE · POWERED BY INTELFUSIONS.COM

GHSA-qfrw-5rxm-mhh2: Mistune renderers/html.safe_url: HARMFUL_PROTOCOLS list misses legacy and chained schemes that historically chain to `javascript:` execution

mediumCVSS 6.1CVE-2026-59929
Summary Type: URL-scheme allowlist gap. The safe_url filter only blocks the four schemes javascript:, vbscript:, file:, data:. Several other schemes are accepted into rendered <a href="..."> and <img src="..."> tags despite being known XSS vectors in legacy or chain-handling browsers. The same gap applies to direct links, reference links, and autolinks. File: src/mistune/renderers/html.py, line 11-23 (HARMFUL_PROTOCOLS list). Root cause: the HARMFUL_PROTOCOLS tuple is a hardcoded, opt-out denylist of four entries. Browsers historically supported (and some still partially support) several other schemes that either execute JavaScript directly (livescript:, mocha:) or wrap a javascript: payload (feed:javascript:, view-source:javascript:, jar:javascript:, ms-its:javascript:, mk:@MSITStore:javascript:). On user-agents that still recognise these schemes (older Firefox builds for feed:/jar:, all Internet Explorer / Edge Legacy for ms-its:/mk:/res:, niche chrome-style browsers, browser extensions that register custom protocol handlers), clicking a link rendered by mistune executes attacker-controlled JavaScript in the page's origin. Affected Code File: src/mistune/renderers/html.py, lines 10-62. class HTMLRenderer(BaseRenderer): HARMFUL_PROTOCOLS: ClassVar[Tuple[str, ...]] = ( "javascript:", "vbscript:", "file:", "data:", ) # <-- BUG: incomplete denylist GOOD_DATA_PROTOCOLS: ClassVar[Tuple[str, ...]] = ( "data:image/gif;", "data:image/png;", "data:image/jpeg;", "data:image/webp;", ) def safe_url(self, url: str) -> str: if self._allow_harmful_protocols is True: return escape_text(url) _url = url.lower() if self._allow_harmful_protocols and _url.startswith(tuple(self._allow_harmful_protocols)): return escape_text(url) if _url.startswith(self.HARMFUL_PROTOCOLS) and not _url.startswith(self.GOOD_DATA_PROTOCOLS): return "#harmful-link" return escape_text(url) # <-- BUG: any scheme not in HARMFUL_PROTOCOLS passes through Why it's wrong: an opt-out denylist for URL schemes i

Details

Source
GitHub Security Advisories (INTL · database · site)
Severity
medium — CVSS 6.1
Published
2026-07-20
Last updated
2026-07-20
Exploitation
Not in CISA KEV at last sync

Original advisory: https://github.com/advisories/GHSA-qfrw-5rxm-mhh2

Exploitation outlook

EPSS (FIRST.org) estimates each CVE’s probability of exploitation in the next 30 days — here is the CSIRTS.com read on those numbers.

Referenced CVEs

CVECSIRTS overviewExternal
CVE-2026-59929coverage & exploitation statusNVD · CVE.org

Same CVEs, other sources

How other CERTs, PSIRTs and databases cover the vulnerabilities in this advisory.

More from GitHub Security Advisories