CVE-2026-40110: Jupyter Server: CORS bypass via regex anchor omission

GHSA-24qx-w28j-9m6p HIGH
Published May 5, 2026
CISO Take

Jupyter Server's Origin header validation uses re.match() instead of re.fullmatch(), allowing any attacker who controls a domain starting with the trusted pattern (e.g., trusted.example.com.evil.com) to bypass CORS protections entirely. With 1,862 downstream dependents and Jupyter's near-universal presence in AI/ML development environments, this creates a wide cross-origin attack surface where a malicious web page can reach the Jupyter kernel API and execute arbitrary code against any unpatched instance — the EPSS places this in the top 87th percentile for exploitation likelihood despite low absolute probability. Patch to jupyter-server 2.18.0 immediately; if patching is not possible, anchor all allow_origin_pat values with ^ and $ as an interim workaround.

Sources: NVD GitHub Advisory EPSS OpenSSF ATLAS

What is the risk?

HIGH risk for organizations where Jupyter Server is deployed on internal networks or developer workstations accessible from a browser. The vulnerability is straightforward to weaponize — an attacker needs only to register a domain that begins with the trusted prefix and serve a malicious page. Jupyter's kernel API permits arbitrary Python execution, so a successful CORS bypass grants effectively full code execution on the server with the process owner's privileges, making this a high-impact stepping stone into AI/ML development pipelines.

How does the attack unfold?

Infrastructure Setup
Attacker registers a domain crafted to match the victim's allow_origin_pat regex prefix (e.g., trusted.example.com.evil.com), exploiting re.match()'s lack of end anchoring.
AML.T0008.002
CORS Validation Bypass
Victim developer visits attacker-controlled page; browser sends the crafted Origin header which passes Jupyter Server's unanchored regex check and receives permissive CORS headers in response.
AML.T0049
Kernel API Exploitation
Attacker's JavaScript enumerates active kernels and posts execute requests to Jupyter's kernel API, achieving arbitrary Python code execution under the server process's privileges.
AML.T0049
AI Artifact Exfiltration
Executed code reads notebooks, model weights, embedded cloud credentials, and training datasets from the development environment and exfiltrates them to attacker infrastructure.
AML.T0035

What systems are affected?

Package Ecosystem Vulnerable Range Patched
Jupyter pip <= 2.17.0 2.18.0
13.2K OpenSSF 5.8 1.9K dependents Pushed 6d ago 79% patched ~9d to patch Full package profile →

Do you use Jupyter? You're affected.

How severe is it?

CVSS 3.1
N/A
EPSS
0.4%
chance of exploitation in 30 days
Higher than 28% of all CVEs
Exploitation Status
No known exploitation
Sophistication
Moderate

What should I do?

5 steps
  1. Patch: Upgrade jupyter-server to 2.18.0 (commits 057869a and 49b3439 resolve the issue).

  2. Workaround: Immediately audit all allow_origin_pat configuration values and wrap each pattern with ^ and $ anchors (e.g., change trusted\.example\.com to ^trusted\.example\.com$).

  3. Network controls: Restrict Jupyter Server access to localhost or trusted internal subnets; never expose Jupyter directly to the internet.

  4. Audit dependents: Check whether downstream packages (JupyterLab, JupyterHub, notebook) in your environment pull jupyter-server <= 2.17.0 and upgrade those dependency chains.

  5. Detection: Monitor web proxy and WAF logs for cross-origin requests to Jupyter endpoints (/api/kernels, /api/sessions) from unexpected origins.

What does CISA's SSVC say?

Decision Track
Exploitation none
Automatable No
Technical Impact total

Source: CISA Vulnrichment (SSVC v2.0). Decision based on the CISA Coordinator decision tree.

How is it classified?

Which compliance frameworks are affected?

This CVE is relevant to:

EU AI Act
Article 15 - Accuracy, robustness and cybersecurity
ISO 42001
A.6.2.6 - Security of AI system development environments
NIST AI RMF
MANAGE-2.2 - Mechanisms to sustain the value of deployed AI systems are evaluated and improved
OWASP LLM Top 10
LLM05:2025 - Supply Chain Vulnerabilities

Frequently Asked Questions

What is CVE-2026-40110?

Jupyter Server's Origin header validation uses re.match() instead of re.fullmatch(), allowing any attacker who controls a domain starting with the trusted pattern (e.g., trusted.example.com.evil.com) to bypass CORS protections entirely. With 1,862 downstream dependents and Jupyter's near-universal presence in AI/ML development environments, this creates a wide cross-origin attack surface where a malicious web page can reach the Jupyter kernel API and execute arbitrary code against any unpatched instance — the EPSS places this in the top 87th percentile for exploitation likelihood despite low absolute probability. Patch to jupyter-server 2.18.0 immediately; if patching is not possible, anchor all allow_origin_pat values with ^ and $ as an interim workaround.

Is CVE-2026-40110 actively exploited?

No confirmed active exploitation of CVE-2026-40110 has been reported, but organizations should still patch proactively.

How to fix CVE-2026-40110?

1. Patch: Upgrade jupyter-server to 2.18.0 (commits 057869a and 49b3439 resolve the issue). 2. Workaround: Immediately audit all allow_origin_pat configuration values and wrap each pattern with ^ and $ anchors (e.g., change trusted\.example\.com to ^trusted\.example\.com$). 3. Network controls: Restrict Jupyter Server access to localhost or trusted internal subnets; never expose Jupyter directly to the internet. 4. Audit dependents: Check whether downstream packages (JupyterLab, JupyterHub, notebook) in your environment pull jupyter-server <= 2.17.0 and upgrade those dependency chains. 5. Detection: Monitor web proxy and WAF logs for cross-origin requests to Jupyter endpoints (/api/kernels, /api/sessions) from unexpected origins.

What systems are affected by CVE-2026-40110?

This vulnerability affects the following AI/ML architecture patterns: ML development environments, Training pipelines using notebook orchestration, JupyterHub multi-user deployments, MLOps pipelines with programmatic notebook execution, Data science workstations with browser-accessible Jupyter.

What is the CVSS score for CVE-2026-40110?

No CVSS score has been assigned yet.

What is the AI security impact?

Affected AI Architectures

ML development environmentsTraining pipelines using notebook orchestrationJupyterHub multi-user deploymentsMLOps pipelines with programmatic notebook executionData science workstations with browser-accessible Jupyter

MITRE ATLAS Techniques

AML.T0008.002 Domains
AML.T0025 Exfiltration via Cyber Means
AML.T0035 AI Artifact Collection
AML.T0049 Exploit Public-Facing Application

Compliance Controls Affected

EU AI Act: Article 15
ISO 42001: A.6.2.6
NIST AI RMF: MANAGE-2.2
OWASP LLM Top 10: LLM05:2025

What are the technical details?

Original Advisory

Jupyter Server uses `re.match()` to validate the Origin header against the `allow_origin_pat` configuration. Since `re.match()` only anchors at the start of the string, an attacker who controls a domain like `http://trusted.example.com.evil.com/` passes validation against a pattern intended to match only `trusted.example.com`. ### Impact <=2.17.0 ### Patches 057869a327c46730afede3eab0ca2d2e3e74acea, 49b34392feaa97735b3b777e3baf8f22f2a14ed8 ### Workarounds Wrap your `allow_origin_pat` value with `^` and `$` ### References https://github.com/jupyter-server/jupyter_server/pull/603 https://docs.python.org/3/library/re.html#re.fullmatch https://docs.python.org/3/library/re.html#re.match

Exploitation Scenario

An adversary targeting an AI development team registers trusted.example.com.evil.com — a domain crafted to match the victim's allow_origin_pat regex at the start while appending an attacker-controlled suffix. They deploy a malicious page on this domain with JavaScript that fetches the list of active Jupyter kernels (GET /api/kernels), selects one, and posts an execute request (POST /api/kernels/<id>/execute) containing Python code to read notebook files, harvest embedded cloud API keys or model registry tokens, and exfiltrate them to the attacker's infrastructure. A targeted phishing email lures a developer to visit the malicious page; since the browser sends the crafted Origin header and Jupyter's re.match() check passes, CORS headers are returned, the browser lifts the same-origin restriction, and the JavaScript silently exfiltrates the environment's AI artifacts without any user interaction beyond the initial page load.

Weaknesses (CWE)

CWE-777 — Regular Expression without Anchors: The product uses a regular expression to perform neutralization, but the regular expression is not anchored and may allow malicious or malformed data to slip through.

  • [Implementation] Be sure to understand both what will be matched and what will not be matched by a regular expression. Anchoring the ends of the expression will allow the programmer to define an allowlist strictly limited to what is matched by the text in the regular expression. If you are using a package that only matches one line by default, ensure that you can match multi-line inputs if necessary.

Source: MITRE CWE corpus.

Timeline

Published
May 5, 2026
Last Modified
May 5, 2026
First Seen
May 5, 2026

Related Vulnerabilities