jupyterlab · Mistune renderers/html.safe_url: HARMFUL_PROTOCOLS list misses legacy and chained schemes that historically chain to
Affects jupyterlabSource GCVE Database
Mentioned vulnerabilities
Not known to be exploited · CVSS 6.1 Medium : upgrade to 4.6.1 when convenient.
Data as of 30 Oct 2026, 07:30 UTC
- Patch
- Available – fixed in 4.6.1
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:NExploitation evidence
Disclosed: evidence found.
CVE published 8 Jul 2026
Detectable: no evidence on record.
No public nuclei template indexed
Weaponized: no evidence on record.
No public exploit code indexed in Metasploit or Exploit-DB
Exploited in the wildExploited: no evidence on record.
Not in CISA KEV and no source reports exploitation
Observed by OffSeq MirageSeen by Mirage: no evidence on record.
No attack traffic recorded by OffSeq Mirage sensors
A missing step is not evidence of safety. Sources: cve.org (opens in a new tab), the Metasploit, Exploit-DB and nuclei-templates index as of 29 Oct 2026.
What to do
Upgrade jupyterlab to 4.6.1.
Affected software
| Product | Affected | Fixed in |
|---|---|---|
Homebrewjupyterlabpkg:brew/jupyterlabOther threats | Affected
| Fixed in
|
Check your own hosts for these packages with threat-finder (opens in a new tab), our free open-source scanner.
Description
## 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. ```python 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 is the wrong shape. The set of schemes a user-agent might honour is unbounded (registered handlers, browser extensions, OS-level protocol registrations, custom intent handlers on Android, etc.), but the set of schemes a markdown renderer needs to allow is small (`http://`, `https://`, `mailto:`, optionally `tel:`, `ftp:`, fragment-only `#anchor`, and a few image-only `data:` types). Switching to an opt-in allowlist with a `safe_extra_protocols` knob for callers who need others would close every variant of this bug class permanently. The current code accepts every chained-scheme XSS vector for as long as the project remembers to keep the denylist current. ## Exploit Chain 1. Application accepts attacker-supplied markdown and renders it with mistune. The default `escape=True` prevents raw HTML, but link href/image src filtering is the only XSS defense for `[click](...)` and `` syntax. 2. Attacker writes `[click here](feed:javascript:alert(document.cookie))`. mistune's `safe_url` checks `feed:javascript:alert(document.cookie)` against `HARMFUL_PROTOCOLS = ('javascript:', 'vbscript:', 'file:', 'data:')` — none match. The href is escape_text'd (HTML-entity escape) and emitted as `<a href="feed:javascript:alert(document.cookie)">click here</a>`. 3. Victim using a Firefox build that still has the feed handler registered (extension, configuration, or LTS that retained the feed reader past the 64.0 removal — including some forks and ESR builds) clicks the link. Firefox's feed handler invokes the inner URL, which is `javascript:alert(...)`. JS executes in the page's origin. Victim's session cookie is exfiltrated. 4. Same pattern for `livescript:alert(1)` (Netscape Communicator era, still recognised by some niche browsers / browser-emulator tools), `view-source:javascript:alert(1)` (Firefox, see CVE-2009-1938), `jar:javascript:alert(1)` (older Firefox), `ms-its:javascript:` (IE/Edge Legacy), `res:javascript:` (IE), `mk:@MSITStore:javascript:` (IE CHM viewer). Each user-agent that recognises one of these is exploitable; the user-agent population that recognises at least one is not negligible (corporate environments still running Edge Legacy compatibility mode, locked-down kiosk browsers, Android WebView in apps that register custom intent handlers, Linux distros with old Firefox ESR plus the `feed:` extension, etc.). The same primitive applies to image src (`` rendered as `<img src="feed:...">`) — though most browsers don't fetch javascript: from img src, the same chained handler quirk applies on a few user-agents — and to reference links and autolinks (verified in the PoC below; the rendered HTML
References
- github.com/lepture/mistune/security/advisories/GHSA-qfrw-5rxm-mhh2 (opens in a new tab)
- nvd.nist.gov/vuln/detail/CVE-2026-59929 (opens in a new tab)
- github.com/lepture/mistune/commit/c7101fcbb6e8790e8e39157c5ca2238fc6dd6cbc (opens in a new tab)
- github.com/lepture/mistune (opens in a new tab)
- github.com/lepture/mistune/releases/tag/v3.3.0 (opens in a new tab)
- github.com/pypa/advisory-database/tree/main/vulns/mistune/PYSEC-2026-2217.yaml (opens in a new tab)