CVE-2026-64849 — MLflow Unauthenticated SSRF, Cloud Credential Theft via Webhook Redirect / DNS-Rebind Bypass
_validate_webhook_url guard via unvalidated HTTP redirects or DNS-rebinding TOCTOU, reaching cloud instance-metadata services (169.254.169.254 / 169.254.170.2) and reflecting IAM credentials back to the attacker. Active in-the-wild exploitation within hours of CVE assignment; CISA KEV, federal deadline 2026-09-02.Executive Summary
CVE-2026-64849 (CVSS 3.1: 9.3 Critical, GHSA-7gwp-5pfp-969j) is an unauthenticated Server-Side Request Forgery in MLflow's model-registry webhook delivery mechanism, affecting all MLflow versions before 3.15.0. MLflow is a Linux Foundation-backed, open-source AI/ML engineering platform with 27,000+ GitHub stars and 60M+ monthly downloads. The default MLflow Tracking Server ships with no authentication at all, and exposes an unauthenticated POST /api/2.0/mlflow/webhooks/{id}/test endpoint that synchronously delivers a webhook test request and returns the upstream response_status and response_body verbatim to the caller — a full-read SSRF primitive by design.
MLflow already validates webhook URLs via _validate_webhook_url() (added in 3.10.0), which resolves the hostname and rejects any URL that resolves to a non-public IP. Two independent bypasses defeat this guard: (1) the validated URL is fetched with default HTTP-redirect-following behavior, so a webhook pointed at an attacker-controlled server that responds with a 302/307/308 redirect to http://169.254.169.254/... is never re-validated at the new Location; and (2) per the original GitHub vulnerability report, the validation function resolves the hostname via socket.getaddrinfo() and then discards the resolved IP — the subsequent delivery request (session.post(webhook.url)) independently re-resolves the same hostname, so a DNS-rebinding attacker can return a public IP at validation time and a private/link-local IP at delivery time (a classic TOCTOU gap). Both mechanisms let an attacker make the MLflow server itself issue a request to the cloud instance-metadata service and read the reflected response.
watchTowr's Attacker Eye global honeypot network observed indiscriminate scanning for exposed MLflow instances within hours of CVE assignment on 2026-08-17. Public reporting attributes confirmed follow-on impact to attackers who successfully exfiltrated cloud credentials: cloud-resource enumeration, cryptominer deployment, and creation of new IAM users/roles for persistence. CISA added the CVE to its Known Exploited Vulnerabilities catalog on 2026-08-19 with a Federal Civilian Executive Branch remediation deadline of 2026-09-02 under BOD 26-04.
Defender reality check: this is a credential-theft bug, not a malware family — there is no file hash, dropped binary, or C2 domain to hunt for. The single most reliable Falcon-native detection signal is the outbound network connection the MLflow server process itself makes to the cloud metadata address once SSRF succeeds (Section 8, Q1/Q2). Everything downstream of that moment — the attacker's actual use of the stolen credentials against the cloud provider's API — happens entirely in the cloud control plane and is invisible to Falcon endpoint telemetry without CloudTrail/GCP Audit Logs/Azure Activity Log ingestion. This pack is built and framed around that reality: the highest-leverage move available to a defender is not detection at all, it's enforcing IMDSv2 (Section 12), which can neutralize the credential-theft payoff even if the SSRF itself is never patched or caught.
Defender priority: patch every internet- or broad-network-reachable MLflow Tracking Server to ≥ 3.15.0 immediately, and separately enforce IMDSv2 with a hop limit of 1 on every cloud host running MLflow — the two controls are independent and both matter, since IMDSv2 enforcement remains protective even against a future, still-unpatched SSRF bug in this or any other application on the same host.Source Review & Web Hunter Notes
Ten sources were fetched and saved verbatim to the pack's sources directory during the research stage. No prompt-injection or agent-directed instructions were found in any fetched content.
| # | Source | Tier | Type | Contribution |
|---|---|---|---|---|
| 1 | GitHub Advisory GHSA-7gwp-5pfp-969j | T1 | Vendor/platform primary | CVSS vector, affected/patched versions, redirect-bypass mechanism, PoC summary with reflected-response example |
| 2 | MLflow PR #24258 (fix commit) | T1 | Vendor primary, source code | Exact patch design (SSRFProtectedHTTPAdapter, connect-time peer-IP validation), confirms DNS-rebinding as the root cause, test coverage description |
| 3 | MLflow Issue #24179 (original report) | T1 | Vendor primary, source code | Line-numbered vulnerable code (validation.py:889-936, delivery.py:153,189), full DNS-rebinding attack timeline, suggested fix, auth-model caveat |
| 4 | MLflow v3.15.0 Release Notes | T1 | Vendor primary | Confirms fix shipped in 3.15.0 alongside unrelated feature work; identifies a second, unrelated security fix in the same release (PR #24571, artifact authorization) |
| 5 | CISA KEV Catalog (official JSON feed) | T1 | Government primary | Official dateAdded/dueDate, CISA's own short description, BOD 26-04 required-action text |
| 6 | The Hacker News | T2 | Reputable press | Exploitation timeline, direct watchTowr quotes (Yordan Ganchev), CISA KEV framing |
| 7 | SecurityWeek | T2 | Reputable press | CVSS confirmation, MLflow adoption stats, BOD 26-04 two-week framing |
| 8 | BleepingComputer | T2 | Reputable press | Attack-vector breakdown (arbitrary internal/loopback requests, IMDS, IAM credential theft, internal port scanning), BOD 26-04 detail |
| 9 | watchTowr / Attacker Eye (via secondary reporting) | T2 | Researcher, corroborated | Honeypot-observed scanning timeline; downstream campaign impact (cryptominer deployment, new IAM user/role creation) as aggregated across multiple outlets citing watchTowr |
| 10 | AWS ECS Developer Guide — Task IAM Role | T1 | Vendor primary (cloud provider) | Confirms 169.254.170.2 as AWS's own documented ECS/Fargate task credentials-proxy address, distinct from the generic EC2 IMDS address 169.254.169.254 |
Contradictions & gaps
- "Unauthenticated" needs one caveat: the original GitHub issue (#24179) describes webhook creation as requiring an "authenticated MLflow user," since the webhook-creation handler lacks a permission decorator. All press and CISA KEV framing this as "unauthenticated" is nonetheless accurate in the vast majority of real-world deployments, because the default MLflow Tracking Server ships with no authentication layer enabled at all — so any network-reachable caller is already an implicit, unrestricted "authenticated" user. Both framings describe the same real-world exposure.
- Two distinct bypass mechanisms are both real and both cited: the GitHub Advisory emphasizes unvalidated HTTP redirects (302/307/308); the original GitHub issue and fix PR emphasize DNS-rebinding TOCTOU. This pack treats both as in-scope, since the shipped fix (connect-time peer-IP validation) closes both simultaneously and press coverage does not always distinguish them.
- The original watchTowr X/Twitter post could not be fetched directly (HTTP 402/paywall) — its quotes are corroborated identically across three independent outlets (thehackernews, securityweek, and secondary aggregators), so confidence in the quoted material remains high despite not reaching the primary post itself.
- No file hashes, C2 domains, or malicious IPs have been published for this CVE's exploitation — expected for a network-protocol-level credential-theft bug rather than a malware family. This pack does not fabricate any.
Hunt Brief & Attack Chain
Hunt brief
| Field | Value |
|---|---|
| Threat name | CVE-2026-64849 — MLflow webhook SSRF (redirect / DNS-rebind bypass of _validate_webhook_url) |
| Affected software | MLflow Tracking Server < 3.15.0 with the model-registry webhook feature reachable over any network the attacker can reach (default install: unauthenticated) |
| Threat actor(s) | Unattributed, opportunistic mass scanning — no named campaign or actor group identified in any fetched source |
| Severity assessment | Critical — unauthenticated, network-reachable, active in-the-wild exploitation, direct path to cloud credential theft |
| CISA KEV | Added 2026-08-19; FCEB remediation due 2026-09-02 (BOD 26-04) |
Attack chain
| # | Step | Detail |
|---|---|---|
| 1 | Recon | Attacker (or, per watchTowr's honeypot data, an automated scanner) discovers an internet-exposed MLflow Tracking Server — default install has no authentication |
| 2 | Webhook setup | Attacker registers a webhook whose URL points to attacker-controlled public infrastructure. _validate_webhook_url() passes because the domain currently resolves to a public IP |
| 3 | Trigger | Attacker calls the unauthenticated POST /api/2.0/mlflow/webhooks/{id}/test endpoint, which synchronously delivers a test payload and returns response_status + response_body to the caller |
| 4a | Bypass — redirect variant | Attacker's server responds to the delivery request with an HTTP 302/307/308 redirect to http://169.254.169.254/...; MLflow's HTTP client follows the redirect by default without re-validating the new Location |
| 4b | Bypass — DNS-rebind variant | Alternatively, the attacker's authoritative DNS server returns a public IP on the validation-time lookup and 169.254.169.254/127.0.0.1 on the delivery-time lookup; the resolved IP from validation is discarded (validation.py:889-936) and the request re-resolves independently (delivery.py:153,189) |
| 5 | SSRF read | The MLflow server process connects to the cloud instance-metadata service on the attacker's behalf, e.g. GET /latest/meta-data/iam/security-credentials/<role> |
| 6 | Reflection | The metadata service's response body (role name, then live temporary access key / secret key / session token) is captured by MLflow's webhook delivery code and returned verbatim in the /test endpoint's HTTP response to the original, still-unauthenticated caller |
| 7 | Credential theft | Attacker parses the reflected response_body and obtains live, valid, temporary cloud credentials scoped to whatever IAM role/service account the MLflow host was running as |
| 8 | Cloud abuse | Attacker uses the stolen credentials directly against the cloud provider's own API (not through MLflow at all) to enumerate resources |
| 9 | Impact (per public reporting) | Confirmed follow-on actions in some incidents: cryptominer deployment, and creation of new IAM users/roles/access keys for persistence, using whatever permissions the abused instance role granted |
| 10 | Detection blind spot | Steps 2-7 touch no local filesystem and spawn no new process distinguishable from normal webhook-delivery activity. The only host-visible artifacts are the outbound network connection itself (Section 8, Q1/Q2) and the DNS query pattern that preceded it (Q3) — there is no malware sample, dropped file, or registry change to hunt for |
Consolidated IOC Table
This is a network-protocol-level SSRF/credential-theft bug, not a malware family. There are no atomic file hashes, C2 domains, or attacker-controlled IPs published in any fetched source, and none are fabricated here. Every row below is either a well-known, non-secret, universally-documented cloud infrastructure address/path, or a behavioral indicator.
| Type | Value | Confidence | Action | Context | Expiry |
|---|---|---|---|---|---|
| Destination IP (well-known, not secret) | 169.254.169.254 | High | Detect only — never Block/Prevent | AWS EC2/GCP/generic link-local cloud instance-metadata address; the reflected-request target in this SSRF chain. Every legitimate cloud workload needs to reach it — see Section 10 | N/A (protocol-defined, permanent) |
| Destination IP (well-known) | 169.254.170.2 | High | Detect only | AWS ECS/Fargate task metadata (v3/v4) endpoint; equally reachable via this SSRF from containerized MLflow deployments | N/A |
| API endpoint path | /api/2.0/mlflow/webhooks/{id}/test | High | Detect / audit | Unauthenticated test-delivery endpoint that reflects response_status + response_body to the caller — the full-read SSRF primitive itself | N/A |
| API endpoint path | /latest/meta-data/iam/security-credentials/ | Medium | Detect (in reflected response bodies / delivery logs, if logged) | AWS IMDS path returning the IAM role name; appending the role name returns the actual temp credentials | N/A |
| Behavioral | Outbound connection from an MLflow tracking-server process to 169.254.169.254 or 169.254.170.2 | High | Detect | Primary host-visible artifact of successful/attempted exploitation — see Q1/Q2 | N/A |
| Behavioral | Repeated DNS resolution of the same attacker-controlled domain, differing IP classes in quick succession | Medium | Investigate | DNS-rebinding staging pattern — see Q3 | N/A |
| Behavioral / config | A configured MLflow webhook whose URL points to a domain outside the organization's known integrations | High | Detect (config audit) | Attack chain step 2 — see native audit-log hunt, Section 7 | N/A |
| File hash | (none published) | — | — | No malware sample or dropped file exists for this CVE — it is a network-protocol bug, not malware | N/A |
| C2 domain / IP | (none published) | — | — | Attacker infrastructure is per-incident and not disclosed in any fetched source; do not fabricate | N/A |
Affected Surface & Telemetry Matrix
| Surface | Telemetry | Priority | Gap |
|---|---|---|---|
| MLflow Tracking Server hosts (VM/bare-metal) < 3.15.0, webhooks enabled, broadly reachable | NetworkConnectIP4, DnsRequest, ProcessRollup2 — native Falcon sensor telemetry, IF a Falcon sensor is actually installed | Critical | Partial — many ML-engineering hosts are unmanaged/agentless application servers without an EDR agent at all |
| MLflow deployed in Kubernetes/containers (Helm chart, managed ML platforms) | Same event types, if the node has a Falcon sensor/container sensor; pod/namespace-level attribution is not covered by the core telemetry documented here | High | Gap — pod-level context requires Falcon Cloud Security / a container sensor, not assumed present |
| Cloud IAM/identity plane (AWS IAM, GCP IAM, Azure Entra) after credential theft | Cloud provider audit logs (CloudTrail, GCP Audit Logs, Azure Activity Log) — NOT Falcon endpoint telemetry | Critical | Full gap unless Falcon Cloud Security or a SIEM ingesting cloud audit logs is in place |
| MLflow's own webhook configuration/audit trail | MLflow's own database/audit log — not Falcon telemetry at all | High | Full gap unless forwarded as a custom log source; see native audit-log hunts, Section 7 |
| Network perimeter (the malicious HTTP request/response itself) | Falcon has no application-layer HTTP payload visibility on a standard host sensor | Medium | Partial — the actual crafted webhook-create/test HTTP request is invisible to Falcon; only its downstream network side-effect (Q1/Q2) is |
ATT&CK Mapping
| Tactic | Technique | Behavior | Falcon Visibility |
|---|---|---|---|
| Initial Access | T1190 — Exploit Public-Facing Application | Unauthenticated POST to MLflow's webhook create/test API | NO NATIVE VISIBILITY |
| Command & Control (channel abuse) | T1071.001 — Application Layer Protocol: Web Protocols | MLflow's own outbound webhook-delivery HTTP request is (ab)used as the SSRF proxy channel to reach the metadata service | PARTIAL |
| Credential Access | T1552.005 — Unsecured Credentials: Cloud Instance Metadata API | SSRF reaches 169.254.169.254/169.254.170.2 and reflects the response back to the attacker | NATIVE FALCON COVERAGE |
| Discovery (post-theft) | T1526 — Cloud Service Discovery | Attacker enumerates cloud resources using the stolen temporary credentials | NO NATIVE VISIBILITY |
| Persistence (post-theft) | T1136.003 — Create Account: Cloud Account | New IAM users/roles created using the stolen role's permissions, per public reporting | NO NATIVE VISIBILITY |
| Persistence (post-theft) | T1098.001 — Account Manipulation: Additional Cloud Credentials | Additional access keys / trust-policy changes to persist beyond the original token's TTL | NO NATIVE VISIBILITY |
| Impact (post-theft) | T1496 — Resource Hijacking | Cryptominer deployment using stolen cloud compute permissions, per public reporting | NO NATIVE VISIBILITY |
NO NATIVE VISIBILITY = occurs entirely off the MLflow host (application layer, or the cloud control plane) — invisible to Falcon endpoint telemetry under any circumstance without additional log ingestion. PARTIAL = the resulting network connection is visible; its HTTP-level semantics are not. NATIVE FALCON COVERAGE = genuine native Falcon endpoint telemetry, no forwarding required — this is deliberately the single technique this CVE's exploitation cannot avoid touching a host Falcon can see.
Native Audit-Log Hunts
These are manual/scripted checks against MLflow itself and its cloud environment — not CQL. Run these regardless of whether Falcon telemetry shows anything, since several attack-chain steps (2, 3, 6) are only visible here.
1. Webhook configuration audit
Enumerate every configured webhook via the MLflow REST API (GET /api/2.0/mlflow/webhooks) or directly against the backend store's webhooks table. Flag any webhook URL whose domain is not on an explicit allowlist of known-good internal/SaaS integration endpoints (Slack, PagerDuty, internal CI, etc.). Any unexpected external domain indicates attack-chain Step 2 has already occurred.
2. Version / patch audit
mlflow --version # Expect: 3.15.0 or later. Anything below is vulnerable today regardless of network exposure.
3. Exposure audit
From outside the corporate network, confirm whether the MLflow Tracking Server's port (commonly 5000 for mlflow server/mlflow ui — confirm your deployment's actual configured port) is reachable from the internet at all. Given watchTowr's honeypot data showing scanning began within hours of disclosure, treat any confirmed-exposed, unpatched instance as compromised-until-proven-otherwise and proceed directly to Section 14 (Containment Runbook).
4. Webhook delivery log review
If MLflow's webhook delivery logs/audit trail are retained, review delivery history for any deliveries that returned HTTP 3xx redirects, or response bodies containing strings such as AccessKeyId, SecretAccessKey, Token, iam/security-credentials, or GCP/Azure metadata-response markers. Any hit indicates the reflection step (attack-chain Step 6) actually completed — not just an attempt.
5. SSRF-guard environment variable audit
# Confirm these are NOT loosened anywhere in your deployment (env vars, container specs, Helm values): MLFLOW_WEBHOOK_ALLOW_PRIVATE_IPS # must be false/unset in production -- true fully disables the SSRF guard MLFLOW_WEBHOOK_ALLOWED_SCHEMES # default ["https"]; confirm not loosened to allow http or other schemes
CrowdStrike LogScale CQL Hunt Queries
All IOCs for this threat are behavioral, not atomic (Section 4) — every query below hunts for the network/process side-effects of exploitation, not a hash or C2 domain. None of these queries require special log forwarding; they run against native Falcon endpoint sensor telemetry.
Looks for: the core exploitation signal — any process on a Falcon-covered host connecting outbound to the AWS/GCP link-local metadata address or the AWS ECS/Fargate task-metadata address. Requires: native NetworkConnectIP4 telemetry, no forwarding needed. Broadest of the two metadata-connection queries; Q2 narrows this to MLflow processes specifically.
// HUNT: CVE-2026-64849 - T1552.005 Unsecured Credentials: Cloud Instance Metadata API // CONF: high FP: medium COST: low | REQUIRES: NetworkConnectIP4 (native Falcon sensor telemetry) // HYPOTHESIS: Successful SSRF exploitation (of this CVE or any other SSRF bug on the host) makes a local process connect outbound to the cloud instance-metadata service to read IAM credentials or role/config data. // LOOKBACK: 14d // FALSE POSITIVES: legitimate AWS SDK (boto3)/cloud-init/instance-agent credential-refresh calls to IMDS from the SAME host for unrelated, benign applications; container orchestration agents (kubelet, ECS agent) also legitimately call metadata endpoints. // TUNING: exclude your environment's known/allowlisted instance-agent and SDK processes (cloud-init, amazon-ssm-agent, ecs-agent, kubelet) by ImageFileName once baselined; prioritize hits where the connecting process is the MLflow server itself (see Q2). #event_simpleName = NetworkConnectIP4 | in(RemoteAddressIP4, values=["169.254.169.254", "169.254.170.2"]) | rename(field=ContextProcessId_decimal, as=TargetProcessId_decimal) | join(query={#event_simpleName = ProcessRollup2}, field=[aid, TargetProcessId_decimal], include=[ImageFileName, CommandLine, UserName]) | table([@timestamp, ComputerName, UserName, ImageFileName, CommandLine, RemoteAddressIP4, RemotePort, aid]) | sort(@timestamp, order=desc)
Looks for: Q1 narrowed to processes whose command line identifies them as an MLflow server — the single highest-confidence signal in this pack, and the recommended Custom IOA candidate (Section 9). An MLflow tracking-server process has no legitimate reason to connect to the link-local metadata range as part of normal webhook/model-registry operation.
// HUNT: CVE-2026-64849 - T1552.005 Unsecured Credentials: Cloud Instance Metadata API (MLflow-specific) // CONF: high FP: low COST: low | REQUIRES: NetworkConnectIP4 + ProcessRollup2 join (native Falcon sensor telemetry) // HYPOTHESIS: The MLflow Tracking Server process, identifiable by "mlflow" in its command line, connects to the cloud metadata address as a direct result of the webhook-delivery SSRF bypass. // LOOKBACK: 14d // FALSE POSITIVES: low. If your MLflow deployment's own artifact store (S3/GCS/Azure Blob) relies on the SAME instance role and the app-level SDK independently calls IMDS for its own credential refresh, expect occasional benign hits from this exact process -- distinguish via the delivery-log audit in Section 7.4. // TUNING: none required for most environments; if benign hits appear, correlate timing against Section 7's webhook delivery log to confirm whether a /webhooks/*/test call immediately preceded the connection. #event_simpleName = NetworkConnectIP4 | in(RemoteAddressIP4, values=["169.254.169.254", "169.254.170.2"]) | rename(field=ContextProcessId_decimal, as=TargetProcessId_decimal) | join(query={#event_simpleName = ProcessRollup2}, field=[aid, TargetProcessId_decimal], include=[ImageFileName, CommandLine, UserName]) | CommandLine = /mlflow/i | table([@timestamp, ComputerName, UserName, ImageFileName, CommandLine, RemoteAddressIP4, RemotePort, aid]) | sort(@timestamp, order=desc)
Looks for: a domain queried repeatedly in a short window from any host — consistent with the DNS-rebinding variant of this bypass, where the attacker's DNS server must be re-queried between webhook validation and delivery. Note: Falcon's DnsRequest event does not expose the resolved IP address in a directly comparable field, so this query detects the repeat-query pattern only, not a confirmed IP change — see TUNING for how to confirm.
// HUNT: CVE-2026-64849 - T1071.001 Application Layer Protocol (DNS-rebinding staging for the webhook SSRF bypass) // CONF: medium FP: medium COST: medium | REQUIRES: DnsRequest (native Falcon sensor telemetry) // HYPOTHESIS: A DNS-rebinding attack requires the same domain to be re-queried and re-resolved between webhook validation and webhook delivery -- an unusually high query count for one domain in a short window from one host is consistent with this staging, though not by itself conclusive. // LOOKBACK: 7d // FALSE POSITIVES: medium-high standalone. Legitimate short-TTL DNS records (CDNs, load balancers, some SaaS integrations, DNS-based health checks) also re-resolve frequently; this alone does not confirm rebinding. // TUNING: do NOT alert on this standalone. Escalate only when a hit here for a given ComputerName is followed within minutes by a Q1 or Q2 hit on the SAME host -- that combination (repeat DNS lookup immediately followed by an IMDS connection) is the confirming pattern for the DNS-rebind bypass variant specifically. #event_simpleName = DnsRequest | !DomainName = /\.(internal|corp|local|arpa)$/i | groupBy([ComputerName, DomainName], function=[count(as=QueryCount), collect(@timestamp, limit=20)], limit=1000) | test(QueryCount >= 5) | sort(QueryCount, order=desc)
Looks for: reconnaissance/exploitation traffic reaching the MLflow Tracking Server's listening port from outside the organization's known internal ranges — the network-layer trace of watchTowr's observed "scanning within hours of disclosure" pattern. Caveat: if the MLflow server sits behind a load balancer or reverse proxy, RemoteAddressIP4 will show the proxy's IP, not the original attacker — correlate with proxy/LB logs if this is your topology.
// HUNT: CVE-2026-64849 - T1190 Exploit Public-Facing Application (reconnaissance / exploitation traffic reaching the exposed endpoint) // CONF: medium FP: medium COST: medium | REQUIRES: NetworkReceiveAcceptIP4 (native Falcon sensor telemetry); REPLACE the port below with your deployment's actual configured MLflow port if not the common default 5000 // HYPOTHESIS: Legitimate MLflow clients (CI/CD runners, data-science workstations, internal load balancers) originate from known internal ranges; connections from outside those ranges to the tracking-server port are consistent with the scanning/exploitation activity reported by watchTowr. // LOOKBACK: 7d // FALSE POSITIVES: legitimate remote data-science users, VPN-sourced traffic that doesn't fall in the excluded CIDRs below, or a reverse proxy/load balancer whose own IP is the only address this query will ever see. // REQUIRED TUNING: replace the three documentation-only RFC1918 exclusions below with your actual internal CIDR ranges (including any VPN/remote-access ranges you consider "internal") before relying on this operationally. #event_simpleName = NetworkReceiveAcceptIP4 | LocalPort = 5000 | !cidr(RemoteAddressIP4, subnet="10.0.0.0/8") | !cidr(RemoteAddressIP4, subnet="172.16.0.0/12") | !cidr(RemoteAddressIP4, subnet="192.168.0.0/16") | table([@timestamp, ComputerName, RemoteAddressIP4, LocalPort, aid]) | sort(@timestamp, order=desc)
Looks for: defense-in-depth enrichment only — this CVE alone grants credential theft, not code execution, so there is no expected process-spawn artifact from exploitation itself. This query exists to catch a secondary issue on the same host that might otherwise be missed while investigating an SSRF finding. Do not alert on this standalone.
// HUNT: CVE-2026-64849 - defense-in-depth enrichment (no ATT&CK technique directly maps -- this CVE grants credential theft, not code execution) // CONF: low FP: high COST: low | REQUIRES: ProcessRollup2 parent-child telemetry (native Falcon sensor) // HYPOTHESIS: This CVE does not grant remote code execution. Any child process spawned by the MLflow server process is therefore NOT explained by this CVE and warrants investigation as a potentially unrelated finding (misconfiguration, a different vulnerability, or legitimate but unbaselined automation). // LOOKBACK: 14d // FALSE POSITIVES: very high standalone -- legitimate MLflow child processes include pip/conda package installs, git operations, and model-serving subprocesses during normal operation. // TUNING: baseline your environment's normal MLflow child-process set before treating any hit as suspicious; only escalate a hit that also correlates with a Q1/Q2/Q3 hit on the same host and time window. #event_simpleName = ProcessRollup2 | CommandLine = /mlflow/i | rename(field=TargetProcessId_decimal, as=ParentProcessId_decimal) | join(query={#event_simpleName = ProcessRollup2}, field=[aid, ParentProcessId_decimal], include=[FileName, CommandLine, UserName]) | table([@timestamp, ComputerName, UserName, FileName, CommandLine, aid]) | sort(@timestamp, order=desc)
Coverage honesty: Q1 and Q2 are the only queries here that directly observe the CVE's core impact (credential theft via metadata access) and are the recommended operational priority. Q3 and Q4 are staging/reconnaissance signals with meaningfully higher false-positive rates — use them for correlation and enrichment, not standalone alerting. None of these queries can see the actual exploitation HTTP request itself (Section 6); that visibility gap is structural, not a tuning problem.
Custom IOA Recommendations
Q2 (MLflow process → cloud metadata connection) is the strongest candidate for promotion to a Custom IOA: it is the single behavior that most directly and unambiguously represents this CVE's actual impact, with low expected false-positive volume in most environments.
Custom IOA Rule: MLflow Process Connecting to Cloud Instance-Metadata Service
| Field | Value |
|---|---|
| Rule Group | Credential Theft / Cloud Metadata Abuse |
| Rule Type | Network Connection (process image/command line + destination IP) |
| Action | Detect (do not promote to Block without validating false-positive rate < 5% over 14+ days in your environment) |
| Severity | High |
| MITRE Technique | T1552.005 — Unsecured Credentials: Cloud Instance Metadata API |
Detection logic: process command line matches an MLflow server process (contains mlflow) AND destination IP is in {169.254.169.254, 169.254.170.2}.
Description: the MLflow Tracking Server process has no legitimate operational reason to connect to the cloud instance-metadata service as part of normal webhook or model-registry activity. A connection matching this pattern is the direct, host-visible signature of successful CVE-2026-64849 exploitation.
FP tuning notes: if your MLflow deployment's artifact store (S3/GCS/Azure Blob) legitimately relies on the same instance role and the application's own SDK independently refreshes credentials via IMDS, expect occasional benign hits from this exact process. Distinguish by correlating with the webhook delivery-log audit (Section 7.4) — genuine SSRF-driven calls correlate with an inbound POST to /webhooks/*/test immediately beforehand, while legitimate SDK credential refresh does not.
Recommended validation: run in Detect mode for at least 14 days; cross-reference every hit against Section 7's webhook configuration audit and delivery-log review before considering any escalation toward blocking.
Machine-Readable IOC Appendix
No atomic file hashes, C2 domains, or malicious IPs have been publicly attributed to CVE-2026-64849 exploitation as of the most recent source (2026-08-22) — expected for a network-protocol-level credential-theft bug, not an established malware family. The grouped blocks below ship the actionable, non-fabricated content for this threat: known infrastructure addresses (detect-only, never block), vulnerable endpoint paths, config/audit strings, and patch metadata.
169.254.169.254 # AWS EC2 / GCP / generic link-local IMDS 169.254.170.2 # AWS ECS/Fargate task metadata (v3/v4) # Azure IMDS path (same base address, requires "Metadata: true" header -- see Section 12): # GET http://169.254.169.254/metadata/instance # # These are universal, non-secret, legitimate cloud infrastructure addresses. # NEVER add them to a Prevent/Block IOC list -- every cloud host needs to reach # its own metadata service. Use only as detection pivots (Q1/Q2), paired with # process-context filtering to avoid false positives on legitimate SDK traffic.
POST /api/2.0/mlflow/webhooks # webhook creation
POST /api/2.0/mlflow/webhooks/{id}/test # unauthenticated test-delivery;
# the full-read SSRF primitive
GET http://169.254.169.254/latest/meta-data/iam/security-credentials/
# AWS IMDS role-name enumeration
GET http://169.254.169.254/latest/meta-data/iam/security-credentials/<role>
# AWS IMDS credential retrieval
MLFLOW_WEBHOOK_ALLOW_PRIVATE_IPS # must be false/unset in prod -- true disables the SSRF guard entirely MLFLOW_WEBHOOK_ALLOWED_SCHEMES # default ["https"]; confirm not loosened Vulnerable code: mlflow/utils/validation.py:889-936 (_validate_webhook_url) Vulnerable code: mlflow/webhooks/delivery.py:153,189 (_send_webhook_request) Fix commit: ba949522477cbd5915aa55d29b0cfad7d5ddf939 (PR #24258)
Vulnerable: MLflow < 3.15.0 Fixed: MLflow >= 3.15.0 GHSA: GHSA-7gwp-5pfp-969j CVSS 3.1: 9.3 (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N) CISA KEV added: 2026-08-19 CISA KEV due: 2026-09-02 (BOD 26-04)
JSON block
{
"cve": "CVE-2026-64849",
"atomic_iocs": [],
"atomic_iocs_note": "No atomic file hashes, C2 domains, or malicious IP addresses have been publicly attributed to CVE-2026-64849 exploitation as of 2026-08-22. This is a network-protocol-level credential-theft vulnerability, not a malware family with distributable artifacts.",
"known_infrastructure_addresses": [
{"type": "ipv4", "value": "169.254.169.254", "role": "cloud-instance-metadata-service", "note": "Universal, non-secret, legitimate cloud infrastructure address. Never add to a Prevent/Block IOC list. Detection pivot only (Q1/Q2)."},
{"type": "ipv4", "value": "169.254.170.2", "role": "aws-ecs-fargate-task-metadata", "note": "Same caveat as above; relevant to containerized MLflow deployments."}
],
"vulnerable_endpoints": [
"POST /api/2.0/mlflow/webhooks",
"POST /api/2.0/mlflow/webhooks/{id}/test"
],
"vulnerable_code": [
{"file": "mlflow/utils/validation.py", "lines": "889-936", "function": "_validate_webhook_url"},
{"file": "mlflow/webhooks/delivery.py", "lines": "153,189", "function": "_send_webhook_request"}
],
"fix_commit": "ba949522477cbd5915aa55d29b0cfad7d5ddf939",
"fix_pr": "https://github.com/mlflow/mlflow/pull/24258",
"vulnerable_versions": "< 3.15.0",
"fixed_version": "3.15.0",
"ghsa": "GHSA-7gwp-5pfp-969j",
"cvss_31_vector": "AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N",
"cvss_31_score": 9.3,
"cisa_kev_date_added": "2026-08-19",
"cisa_kev_due_date": "2026-09-02"
}
Detection Validation Gates
| Gate | Requirement | Status |
|---|---|---|
| Telemetry readiness (Q1, Q2, Q3, Q5) | Falcon sensor installed on every host running MLflow — not guaranteed, since ML-engineering hosts are frequently unmanaged | Verify per-tenant asset inventory before relying on these operationally |
| Telemetry readiness (Q4) | Accurate knowledge of your deployment's actual configured MLflow port and internal/VPN CIDR ranges | Required — the query as shipped uses the common default port and RFC1918 placeholders, see REQUIRED TUNING |
| Benign baseline (Q1/Q2) | Confirm which processes on your MLflow hosts legitimately call IMDS today (cloud-init, SSM agent, the MLflow app's own SDK for its artifact store) before treating any hit as an incident | Run over a known-clean 14-day window first |
| Benign baseline (Q3) | Confirm your environment's normal DNS re-resolution behavior (CDNs, load balancers) so the threshold in test(QueryCount >= 5) is meaningful for your traffic volume | Adjust the threshold per-tenant if noisy |
| Positive test | No safe way to trigger the actual SSRF against your own metadata service for testing purposes. Validate Q1/Q2 instead by confirming they fire against any benign, intentional connection to 169.254.169.254 from a test host/process in a lab environment | Recommended before operational reliance |
| Promotion | Only Q2 is a Custom IOA candidate (Section 9); Q1, Q3, Q4, Q5 remain Detect/Investigate-only by design given their higher false-positive rates | N/A |
Hardening & Mitigation
- Patch every MLflow Tracking Server to ≥ 3.15.0. This is the only complete fix — it closes both the redirect and DNS-rebinding bypass variants via connect-time peer-IP validation. Framework: M1051 (Update Software); MLflow GHSA-7gwp-5pfp-969j, PR #24258. Verify:
mlflow --versionreports 3.15.0 or later on every instance. - Enforce IMDSv2 with a hop limit of 1 on every cloud host running MLflow. This neutralizes the credential-theft payoff of this SSRF (and any future, still-unpatched SSRF bug on the same host) independent of patching, since IMDSv2 requires a session token that a simple reflected-GET SSRF cannot obtain, and the hop-limit blocks metadata requests that traverse an extra network hop (e.g. from inside a container). Framework: MITRE mitigation guidance for T1552.005; AWS IMDSv2 best practice. Deploy:
aws ec2 modify-instance-metadata-options --instance-id <id> --http-tokens required --http-put-response-hop-limit 1. Verify:aws ec2 describe-instances --instance-ids <id> --query "Reservations[].Instances[].MetadataOptions"showsHttpTokens: required,HttpPutResponseHopLimit: 1. - Require authentication in front of the MLflow Tracking Server. The default install has none. Enable MLflow's basic-auth plugin, or front the server with a reverse proxy enforcing SSO/mTLS, so the unauthenticated attack surface this CVE relies on is closed regardless of patch level. Framework: M1032 (Multi-factor Authentication); ⚠ best-practice, no formal MLflow-specific benchmark. Verify:
curl -s -o /dev/null -w "%{http_code}" http://<host>:5000/api/2.0/mlflow/experiments/searchfrom outside returns 401/403, not 200.
- Egress-filter MLflow hosts to an explicit allowlist of legitimate destinations (artifact store endpoint, package registries, internal auth provider). This defeats SSRF exploitation regardless of any future application-layer bug. Framework: M1037 (Filter Network Traffic). Verify: from the host, a request to an arbitrary non-allowlisted domain (e.g.
curl --max-time 3 https://example.com) fails/times out; a request to an allowlisted destination succeeds. - Restrict or disable the webhook feature if not in active use. If in use, restrict webhook creation to admin-only access until MLflow ships native RBAC on webhook creation, and run the Section 7.1 audit weekly. Framework: M1018 (User Account Management). Verify: re-run the Section 7.1 webhook audit and confirm the configured-webhook list matches an approved inventory.
- Apply least-privilege to the IAM role/service account attached to MLflow hosts — scope it to exactly the artifact-store bucket/permissions the deployment needs, nothing broader. This minimizes blast radius even if a credential is stolen. Framework: M1026 (Privileged Account Management). Verify: review the attached policy (
aws iam simulate-principal-policyor manual review) and confirm no wildcard resource/action beyond the artifact-store scope.
- Segment MLflow Tracking Servers into a dedicated network zone with no default route to sensitive internal services and minimal internet exposure. Framework: M1030 (Network Segmentation). Verify: from the MLflow host, confirm connectivity to sensitive internal services (databases, admin panels) not required by MLflow itself is blocked.
- Enable cloud-native SSRF/IMDS-abuse detection (AWS GuardDuty finding types
UnauthorizedAccess:EC2/MetadataDNSRebindandInstanceCredentialExfiltration, Azure Defender for Cloud, GCP Security Command Center) to catch exploitation even where it bypasses host-level Falcon telemetry entirely (Section 6's largest coverage gap). Framework: ⚠ best-practice, cloud-provider guidance, no formal cross-cloud benchmark. Verify: confirm the relevant finding types are enabled and alerting in your cloud security posture management tooling. - Establish a credential/key rotation cadence for any IAM role or service account ever attached to an internet-reachable MLflow host, independent of confirmed compromise — this exploit chain grants live, valid credentials whose value to an attacker doesn't require any further host-level footprint. Framework: credential-hygiene best-practice. Verify: confirm a rotation schedule/ticket exists and the most recent rotation postdates this pack's publication.
Why IMDSv2 matters more than usual here: unlike most SSRF findings where patching the application is the whole story, this CVE's actual payoff (temporary IAM credentials) is entirely defeated by IMDSv2 token enforcement even if the underlying webhook bug is never fixed. Treat IMDSv2 enforcement as independently mandatory, not merely a defense-in-depth nicety.
Deployable Playbooks
Playbook A: Emergency Patch + IMDSv2 Enforcement
Estimated deploy time: 20-40 minutes per host (excluding change-management approval) — Prerequisites: admin access to MLflow hosts and cloud console/CLI; a maintenance window or rolling-restart capability — Reboot required: No (application restart only for the MLflow patch; the IMDSv2 metadata-options change is live on AWS with no instance reboot needed) — Rollback: pip install mlflow==<previous pinned version> reverts the patch but re-exposes the CVE, so document but discourage; for IMDSv2, aws ec2 modify-instance-metadata-options --instance-id <id> --http-tokens optional re-permits IMDSv1 as a temporary bridge only, with a tracked follow-up ticket to re-enforce.
Step 1 — Inventory
Enumerate every MLflow Tracking Server instance and its exact version (Section 7.2).
Step 2 — Patch a canary instance first
pip install --upgrade "mlflow>=3.15.0" # or, for a container deployment, bump the base image tag and redeploy
Step 3 — Restart
Restart the mlflow server process or redeploy the container.
Step 4 — Verify the patch
# Version check mlflow --version # Expect: 3.15.0 or later # Confirm no unexpected webhooks remain configured (Section 7.1) curl -s -H "Authorization: Bearer <token>" http://<host>:5000/api/2.0/mlflow/webhooks | jq . # Functional confirmation: attempt a benign webhook test against a URL you control # that redirects to an internal address you are authorized to test with. Pre-patch # this would succeed and reflect the internal response; post-patch it should be # BLOCKED by the new SSRFProtectedHTTPAdapter.
Step 5 — Enforce IMDSv2 on every affected cloud host
aws ec2 modify-instance-metadata-options \ --instance-id <id> \ --http-tokens required \ --http-put-response-hop-limit 1 # Verify aws ec2 describe-instances --instance-ids <id> \ --query "Reservations[].Instances[].MetadataOptions" # Expect: HttpTokens: required, HttpPutResponseHopLimit: 1
Step 6 — Roll out
Repeat Steps 2-5 across all remaining instances from the Step 1 inventory, sequencing internet-exposed instances first.
Playbook B: Egress Lockdown for MLflow Hosts
Estimated deploy time: 30-60 minutes plus a validation window — Prerequisites: documented knowledge of MLflow's legitimate outbound dependencies (artifact store endpoint, package registries, internal auth provider) — Reboot required: No (security-group/firewall change only) — Rollback: revert the security-group/firewall rule set to the prior permissive baseline via a tracked change ticket; note that reverting re-opens the SSRF blast radius, so treat any rollback as temporary.
Step 1 — Enumerate legitimate destinations
List every destination the MLflow host legitimately needs to reach outbound.
Step 2 — Apply an explicit-allowlist egress policy
# Example: host-level default-deny with explicit allow (nftables) nft add rule inet filter output ip daddr <artifact-store-cidr> accept nft add rule inet filter output ip daddr 169.254.169.254 accept # required for the host's OWN legitimate IMDSv2 calls nft add rule inet filter output policy drop # Equivalent: AWS security group egress rules restricted to the same destination set
Step 3 — Validate
Confirm the host can still reach its artifact store and any package registries it needs. Confirm an arbitrary non-allowlisted domain now fails to connect from the host.
Step 4 — Monitor before treating as baseline
Watch Q1/Q2/Q4 (Section 8) for a period after rollout to catch any unexpected blocked-traffic regressions before treating this as the new permanent baseline.
Containment Runbook
| Phase | Actions | Owner | Evidence to Preserve |
|---|---|---|---|
| 1. Triage | Confirm MLflow patch level; run Section 7's webhook audit and delivery-log review; run Section 8 Q1/Q2 for the suspected window | SOC / ML Platform Team | Version output, webhook list export, delivery-log excerpts, query results |
| 2. Contain | If metadata access is confirmed: immediately revoke/rotate the affected instance role's credentials at the cloud IAM layer — this invalidates any already-stolen temporary token faster than waiting for natural TTL expiry. If exploitation appears ongoing, isolate the MLflow host from network access | Cloud/Platform Security / Incident Commander | Rotation timestamp, isolation action log |
| 3. Eradicate | Patch to ≥ 3.15.0; remove any attacker-registered webhooks found in the audit; rotate the underlying IAM role/service-account long-term credentials, not just the temporary session token | ML Platform Team / Cloud Security | Patch confirmation, removed-webhook list, rotation ticket references |
| 4. Recover & audit cloud usage | Using cloud provider audit logs (CloudTrail / GCP Audit Logs / Azure Activity Log — outside Falcon), review every API call made with the compromised role's credentials during the exposure window, specifically for new IAM users/roles/access keys and unexpected compute/storage resources (cryptomining indicators, per public reporting of this campaign's real-world impact) | Cloud/Identity Security | Audit-log export, list of any newly-created principals or resources |
| 5. Hunt for downstream abuse | Search cloud billing/compute inventory for unexpected instances; search for new IAM principals created outside change-management | Cloud Security / SOC | Inventory diff, any confirmed unauthorized resources escalated as a separate incident |
| 6. Lessons learned | Confirm webhook feature is auth-gated or disabled going forward; confirm IMDSv2 enforcement and egress lockdown (Section 13) landed on every host; determine whether Falcon sensor coverage needs to extend to previously-unmonitored ML infrastructure | Security Engineering | Updated runbook, closed remediation tickets, sensor-coverage gap ticket if applicable |
Detection Coverage Map
| MITRE Technique | Behavior | CQL | Custom IOA | Coverage |
|---|---|---|---|---|
| T1190 | Unauthenticated webhook create/test API abuse | Q4 (network-layer trace only) | — | PARTIAL |
| T1071.001 | Webhook delivery used as SSRF proxy channel | Q3 | — | PARTIAL |
| T1552.005 | Cloud metadata credential theft | Q1, Q2 | IOA-1 | GOOD |
| T1526 | Cloud resource enumeration post-theft | — | — | GAP |
| T1136.003 | New IAM user/role creation | — | — | GAP |
| T1098.001 | Additional cloud credentials added | — | — | GAP |
| T1496 | Cryptominer deployment via stolen compute permissions | — | — | GAP |
Coverage summary: 1 of 7 mapped techniques has good native coverage (the credential-theft moment itself — also the core of this CVE); 2 have partial coverage; 4 are full gaps, all occurring entirely in the cloud control plane and requiring CloudTrail/GCP Audit Logs/Azure Activity Log ingestion (via Falcon Cloud Security or a SIEM) that is not assumed present.
Priority gap: the initial exploitation HTTP request (T1190) and all post-theft cloud-plane abuse (T1526/T1136.003/T1098.001/T1496) are structurally invisible to Falcon endpoint telemetry alone. This pack's genuine, reliable coverage is narrow and specific — the moment of credential theft itself (T1552.005) — which is fortunately also the single highest-leverage moment to preempt entirely: IMDSv2 enforcement (Section 12) defeats the credential-theft payoff regardless of whether detection ever fires.
Validation gates: see Section 11 for telemetry-readiness and baseline requirements before relying on any query above operationally.
Hunt Summary Ticket
TITLE: CVE-2026-64849 -- MLflow Unauthenticated SSRF (Webhook Redirect / DNS-Rebind
Bypass) -- Cloud Credential Theft Hunt
SEVERITY: Critical (CVSS 9.3, unauthenticated, CISA KEV, active ITW exploitation within
hours of disclosure)
SCOPE: All MLflow Tracking Server deployments < 3.15.0 with the webhook feature
reachable from any network the attacker can reach, including internet-exposed
instances (default install has no authentication)
HYPOTHESIS: An unauthenticated attacker registers a webhook pointing to attacker-controlled
infrastructure, triggers the unauthenticated /test endpoint, and uses an HTTP
redirect or DNS-rebinding TOCTOU bypass in _validate_webhook_url to make the
MLflow server issue a request to the cloud instance-metadata service
(169.254.169.254 / 169.254.170.2), reflecting the response -- including live
IAM credentials -- back to the attacker.
QUERIES: Q1 any process -> cloud metadata connection (native Falcon)
Q2 MLflow process -> cloud metadata connection, high confidence (native Falcon)
Q3 repeated DNS resolution of same external domain, rebind-staging signal
Q4 external/internet-sourced inbound connections to MLflow's port
Q5 unexpected child processes of the MLflow server, investigate-only
DO FIRST: 1. Patch every MLflow Tracking Server to >= 3.15.0
2. Enforce IMDSv2 + hop-limit 1 on every cloud host running MLflow
3. Run the Section 7 webhook-configuration audit for attacker-registered webhooks
4. Rotate the IAM role/service-account credentials of any host with a Q1/Q2 hit
FINDINGS: [Analyst fills in after running queries -- Claude cannot execute CQL]
GAPS: The exploitation HTTP request itself (T1190) and all post-theft cloud-control-
plane abuse (resource enumeration, new IAM users, cryptomining) are invisible to
Falcon endpoint telemetry alone -- see Section 15. Genuine native coverage is
narrowly the credential-theft moment itself (T1552.005), which is also the
highest-leverage point to preempt via IMDSv2.
ACTIONS: See Section 12 (Hardening) and Section 14 (Containment Runbook)
OWNER: [Assign: Cloud/Platform Security + ML Engineering + SOC]
VERSION: v0.1 -- 2026-08-22
Changelog
References
| Tier | Source | Used For | Access Date |
|---|---|---|---|
| T1 | GitHub Advisory GHSA-7gwp-5pfp-969j | CVSS vector, affected/patched versions, redirect-bypass mechanism, PoC summary | 2026-08-22 |
| T1 | MLflow PR #24258 (fix commit) | Official patch design and root-cause confirmation | 2026-08-22 |
| T1 | MLflow Issue #24179 (original report) | Line-numbered vulnerable code, DNS-rebinding attack timeline | 2026-08-22 |
| T1 | MLflow v3.15.0 Release Notes | Confirms fix shipped in the named release | 2026-08-22 |
| T1 | CISA KEV Catalog (official JSON feed) | Official dateAdded/dueDate, CISA short description, BOD 26-04 text | 2026-08-22 |
| T2 | The Hacker News | Exploitation timeline, direct watchTowr quotes | 2026-08-22 |
| T2 | SecurityWeek | CVSS confirmation, adoption stats, BOD 26-04 framing | 2026-08-22 |
| T2 | BleepingComputer | Attack-vector breakdown, BOD 26-04 detail | 2026-08-22 |
| T2 | watchTowr / Attacker Eye (via secondary reporting) | Honeypot exploitation timeline, downstream campaign impact | 2026-08-22 |
| T1 | AWS ECS Developer Guide — Task IAM Role | Provenance for 169.254.170.2 as AWS's documented ECS/Fargate credentials-proxy address | 2026-08-22 |