Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
AccessPublish malicious third-party language pack
-
DeliveryVictim installs and selects locale
-
ExploitPrefix-only regex accepts appended JS
-
Executionnew Function executes code in authenticated origin
-
PersistCall authenticated Jupyter Server APIs
-
ImpactRead/modify files and run kernel code
Vulnerability Assessment
| Weakness |
CWE
OWASP Top 10:2025
A05:2025 - Injection
ASVS 5.0
V1 - Encoding and Sanitization Output encoding, context-aware escaping
MITRE ATT&CK
2 techniques across 2 tactics: Initial Access, Execution The technique list with ATT&CK links and the kill-chain view is part of the Basic plan and up. |
| Exploitation Conditions | Exploitation requires a victim to install AND activate a malicious or tampered third-party JupyterLab language pack (locale/translation catalogue); the default English locale is unaffected because it loads no catalogue. The Plural-Forms header must carry a valid plural rule as a matching prefix followed by appended JavaScript, which the prefix-only regex (missing end-anchor) accepts and passes to |
| Impact | The provided CVSS 3.1 vector (AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N) yields 6.8 (Medium) and is internally consistent with the description: exploitation is network-reachable but requires both a high-complexity precondition (the victim must select a malicious third-party language pack) and user interaction (UI:R). No EPSS score, KEV listing, or public POC is present in the input, so this is 'no public exploit identified at time of analysis' - though the fix commit ships a regression test (985a3223) that demonstrates the injection primitive ( |
| Exploit ScenarioDerived | An attacker publishes or tampers with a third-party JupyterLab language pack whose Plural-Forms header contains a valid plural rule followed by appended JavaScript. A user installs and selects that locale; when JupyterLab loads the catalogue and translates any plural string, the appended code runs via |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Sep 29, 2026
Code injection in JupyterLab's translation pipeline allows JavaScript appended to a third-party language pack's Plural-Forms header to be executed in the authenticated JupyterLab origin, because the validation regex accepts a matching prefix without requiring the whole header to match and the expression is later passed to new Function. Affected are JupyterLab 3.0.0 through 4.5.11 and 4.6.4 (exclusive of the fixes), plus JupyterLite Core 0.8.3 and earlier. Exploitation requires the victim to install and select a malicious or tampered third-party locale catalogue (the default English locale loads no catalogue and is unaffected), and unauthenticated remote attackers need user interaction (CVSS:3.1/AV:N/AC:H/PR:N/UI:R), yielding a Medium severity of 6.8; where Jupyter Server kernels, terminals, and APIs are exposed to the JupyterLab origin the injected code can read or modify files and run code, while JupyterLite impact is sharply limited by the usual absence of those surfaces. No public exploit code was identified at time of analysis and the issue is not confirmed actively exploited (CISA KEV).
RemediationAI
Upgrade to a patched release: JupyterLab 4.5.11 or 4.6.4 (releases at https://github.com/jupyterlab/jupyterlab/releases/tag/v4.5.11 and https://github.com/jupyterlab/jupyterlab/releases/tag/v4.6.4) and JupyterLite Core 0.8.4 or later; the fix is the upstream commits 985a3223cd77fd4f991cd90066342a90711d70f6, de324ae91346c713c4f5e5485f97b6e914e0f774, and f9de43dc565a1118120d466117f877a189a4ce90, with the primary change adding the missing end anchor to the Plural-Forms validation regex in packages/translation/src/gettext.ts. Until upgrading, treat third-party language packs as untrusted code: disable or remove non-default locale catalogues so that only the default English locale (which loads no catalogue) is used - the trade-off is loss of localized UI. If non-English translations are required, source catalogues only from vetted, integrity-checked builds and audit each catalogue's Plural-Forms header for content beyond a well-formed 'nplurals=N; plural=(...)' rule, since any trailing JavaScript after a valid rule is the exploitation signature; this manual review is error-prone and not a substitute for patching. Additionally, reduce the value of a successful injection by restricting exposure of Jupyter Server kernels, terminals, and web APIs to the JupyterLab origin, since the assessment notes that file read/modify and code execution depend on those surfaces being reachable - JupyterLite deployments already benefit from their typical absence. No public exploit code or confirmed in-the-wild exploitation was identified at time of analysis, so prioritization should follow the Medium CVSS 6.8 score and the requirement for user interaction rather than emergency response.
Affected VersionsENISA
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 2 packages in pypi
Checking this CVE against your own stacks and servers is part of the Basic plan and up.
Technical ContextAI · show details
The flaw lives in the gettext handling of the @jupyterlab/translation package (packages/translation/src/gettext.ts), which parses the gettext Plural-Forms header from a locale's compiled JSON catalogue. Gettext plural rules are real expressions evaluated to pick a plural form, and JupyterLab implements this by constructing a function via new Function from the parsed expression. The validation regex used to gate the header was prefix-only (it ended with the character class [...] without a trailing $ anchor), so a string such as 'nplurals=2; plural=(n > 1); globalThis.__jupyterLabTranslationXss = true;' satisfies the pattern up to the closing parenthesis while the trailing attacker-controlled JavaScript is still carried into the evaluated expression. The upstream fix (commit 985a3223cd77fd4f991cd90066342a90711d70f6) adds the missing end anchor, converting the pattern to '^\s*nplurals\s*=\s*\d+\s*;\s*plural\s*=[\s\-?|&=!<>+*/%:;n0-9_()]+$', and the accompanying test asserts that a catalogue with appended JavaScript throws 'not valid' rather than setting the injected global. The root cause class is tracked as CWE-79 (improper neutralization of input during web page generation, i.e. cross-site scripting), since the injected payload executes within the JupyterLab web origin with that origin's authenticated context and can therefore reach Jupyter Server web APIs when they are exposed; JupyterLite, which typically does not expose kernels, terminals, or the Jupyter Server API from the same origin, correspondingly limits the blast radius.
Know when JavaScript gets its next vulnerability
- Watch products and get an email when something new is published
- Check this CVE against your own stack and servers
- Exploit and PoC references, threat intelligence from 22 sources
No credit card · 7-day full trial
Severity by source
AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N
Network-reachable but AC:H because the attacker must supply a crafted third-party locale the victim then selects (UI:R); no auth needed (PR:N); code runs in authenticated origin yielding C:H/I:H.
Primary rating from Vendor (github).
CVSS VectorVendor: github
Lifecycle Timeline
2DescriptionCVE.org
JupyterLab is an extensible environment for interactive and reproducible computing, based on the Jupyter Notebook Architecture. From JupyterLab 3.0.0 until 4.5.11 and 4.6.4, and in JupyterLite Core 0.8.3 and earlier, the Plural-Forms header in a selected third-party language pack can append JavaScript after a valid plural rule because prefix-only regular-expression validation accepts a matching prefix without requiring the entire header to match. JupyterLab passes the accepted expression to new Function, so loading the catalogue and translating a plural string executes the appended code in the authenticated JupyterLab origin. Where Jupyter Server kernels, terminals, and APIs are exposed, the code can use authenticated server APIs to read or modify files and run code. Impact is much more limited in JupyterLite because it typically lacks most exposed Jupyter Server surfaces. The default English locale is unaffected because it does not load a translation catalogue. This issue is fixed in JupyterLab 4.5.11 and 4.6.4 and JupyterLite Core 0.8.4.
Blast Radius
ecosystem impact- 5 pypi packages depend on jupyterlab (2 direct, 3 indirect)
Ecosystem-wide dependent count for version 4.6.0.
Threat Intelligence Overview
How this decision was reached
The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.
What every action level means
SSVC AssessmentENISA
Priority Score
Attack Technique
Cross-Site Scripting occurs when an application accepts untrusted data and sends it to a web browser without proper validation or encoding.
More in JavaScript
View allCommand injection in simple-git, the Node.js library for running git commands and published on npm, affects all releases
Stored DOM-based cross-site scripting in Paella Player's closed-caption rendering path (paella-core before 2.12.11) allo
Authorization bypass in Wiki.js through 2.5.314 allows an authenticated user who has been granted access to at least one
Untrusted git configuration includes reachable through simple-git before 4.0.0 let an attacker execute arbitrary command
Improper memory allocation control in ExifReader before 4.41.1 allows remote attackers to exhaust heap memory and termin
Deeply nested brace patterns cause unbounded recursion in the npm brace-expansion library, exhausting the native stack a
Stack exhaustion in the npm library brace-expansion (all versions prior to 1.1.19, 2.1.5, 3.0.7, and 5.0.10) lets a craf
Server-side request forgery in Wiki.js through 2.5.314 lets an authenticated user who holds page-editing permissions for
The JavaScript library ip-address (npm) fails to treat the NAT64 local-use prefix 64:ff9b:1::/48 as private, so applicat
Authorization bypass in the @grpc/grpc-js-xds package (the xDS/RBAC extension for @grpc/grpc-js) lets a request for one
Cross-family subnet comparisons in the ip-address npm library (all versions before 10.7.1) can cause isInSubnet and isHo
Denial of service in the ip-address JavaScript/npm library (all versions prior to 10.7.1) lets remote attackers stall or
EUVD-2026-89337
GHSA-3jqq-pw4j-pqcj
NVD
CVE.org
EPSS
Vulnrichment
Exploit-DB