Introduction
A convenience feature in MLflow's AI Gateway that resolves environment variable references in API key fields turned out to be a direct pipeline from server memory to attacker infrastructure. CVE-2026-4035, scored at CVSS 9.1 (Critical), lets any user (or in default deployments, any unauthenticated network client) exfiltrate arbitrary environment variables from the MLflow server by crafting a gateway secret that points to an attacker-controlled endpoint.
MLflow is the most widely adopted open-source MLOps framework in production environments today. Databricks created it in 2018 to manage the complete machine learning lifecycle. With 26.2k GitHub stars and 5.8k forks, it is foundational infrastructure for ML teams across industries. The MLOps market it anchors is projected to reach approximately $4.39 billion in 2026, so a vulnerability in MLflow's core services matters well beyond any single deployment.
The credential leak is not the worst outcome. Demonstrated exploitation scenarios show that exfiltrated AWS credentials can be used to poison model artifacts in S3. When downstream consumers load those poisoned models, malicious cloudpickle payloads execute arbitrary code in their environments. A credential disclosure vulnerability becomes a supply chain attack vector with cross-boundary code execution.
Technical Information
Root Cause
CVE-2026-4035 is classified under CWE-201 (Insertion of Sensitive Information Into Externally Accessible File or Directory). The flaw is in the _resolve_api_key_from_input() function in mlflow/gateway/config.py. This function unconditionally treated any api_key value starting with $ as an environment variable reference and resolved it against the MLflow server's process environment at runtime. It then sent the resolved secret value in provider authentication headers (such as api-key or authorization) to whatever URL was configured as the upstream api_base.
The vulnerable code path looked like this:
# try reading as an environment variable if api_key_input.startswith("$"): env_var_name = api_key_input[1:]
There was no access control check, no allowlist of permissible environment variables, and no restriction on who could create gateway secrets with $-prefixed values. The api_base parameter was also fully user controlled, so the resolved secret could be sent to any network endpoint.
Attack Flow
The exploitation chain is straightforward and requires only access to the MLflow REST API:
- The attacker creates a gateway secret with
$TARGET_ENVas theapi_keyvalue, whereTARGET_ENVis the name of the environment variable to exfiltrate. For example,{"api_key": "$AWS_SECRET_ACCESS_KEY"}. - They set the
api_baseparameter to a service under their control. This capture server receives the leaked credentials when the gateway makes outbound requests. - They invoke the gateway endpoint (for example,
/gateway/openai/v1/chat/completions). The server resolves the environment variable at runtime and sends the real secret value in outbound HTTP headers to the attacker's capture server.
Authentication Requirements
The authentication barrier for this attack depends on the deployment configuration.
In default MLflow deployments (without basic-auth), the vulnerability requires zero authentication. Any network client that can reach the MLflow server can execute the full attack chain. A separate scanning campaign identified 238 MLflow instances exposed on the internet with unauthenticated HTTP 200 responses on port 5000, which makes this a practical concern.
In basic-auth deployments, low-privileged authenticated users can still exploit the vulnerability. The gateway secret pre-request permission validators do not cover the CreateGatewaySecret endpoint, and creators are automatically granted manage/use permissions on their resources. Any user who can authenticate to the MLflow instance can therefore create the malicious gateway secret configuration.
Escalation to Supply Chain Attack
The most severe demonstrated impact is a supply chain compromise. An attacker can use leaked AWS credentials (AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY) from the MLflow server environment to overwrite model artifacts in S3, replacing python_model.pkl files with malicious cloudpickle payloads. When downstream consumers load the poisoned model, the malicious code executes in their environment, which is cross-boundary remote code execution. One credential leak becomes a compromise of every system that consumes models from the poisoned artifact store.
Patch Information
The fix for CVE-2026-4035 was merged on March 10, 2026 via Pull Request #21544, with commit 4a3f2f7. The patch is included in MLflow version 3.11.0. The Huntr advisory lists the status as Fixed, with CWE-201 classification and a CVSS 3.1 score of 9.1 (Critical).
The fix adds an opt-in boolean flag, MLFLOW_GATEWAY_RESOLVE_API_KEY_FROM_ENV, which defaults to False. It follows a pattern already used for file-based key resolution (MLFLOW_GATEWAY_RESOLVE_API_KEY_FROM_FILE). The main change is a single-line guard in config.py:
- # try reading as an environment variable - if api_key_input.startswith("$"): + # try reading as an environment variable (only for legacy YAML-config gateway) + if api_key_input.startswith("$") and MLFLOW_GATEWAY_RESOLVE_API_KEY_FROM_ENV.get(): env_var_name = api_key_input[1:]
Unless the flag is explicitly enabled, the function now treats any $-prefixed value as a literal string and returns it as is. The string $MY_SECRET stays the literal API key string $MY_SECRET instead of resolving to the contents of the MY_SECRET environment variable.
The flag is defined in mlflow/environment_variables.py:
MLFLOW_GATEWAY_RESOLVE_API_KEY_FROM_ENV = _BooleanEnvironmentVariable( "MLFLOW_GATEWAY_RESOLVE_API_KEY_FROM_ENV", False )
The patch preserves backward compatibility for the legacy YAML-config gateway (mlflow gateway start). Both mlflow/gateway/app.py and mlflow/gateway/runner.py now auto-enable this flag when starting in legacy mode:
os.environ[MLFLOW_GATEWAY_RESOLVE_API_KEY_FROM_ENV.name] = "true"
The modern API-driven gateway, which is the primary attack surface for this vulnerability, is protected by default. The legacy YAML-config gateway, where environment variable resolution is a documented and expected feature, keeps its existing behavior.
The commit also includes a dedicated test (test_api_key_env_resolution_blocked_without_flag) for the new security boundary. It asserts that without the flag set, _resolve_api_key_from_input("$KEY_AS_ENV") returns the literal string "$KEY_AS_ENV" instead of the environment variable's value.
In total, the patch touches 5 files, with 30 additions and 4 deletions. It is a compact, well-scoped fix built on a secure-by-default design.
Caveat for operators: Organizations that run the legacy YAML-config gateway through mlflow gateway start should know that the patch automatically sets the flag to "true" in that code path, which preserves the vulnerable behavior for backward compatibility. Operators who do not need environment variable resolution in gateway secrets should explicitly override this default.
Recommended Mitigation Steps
| Mitigation | Priority | Addresses Unauthenticated Path | Addresses Env Var Exfiltration | Addresses Credential Escalation |
|---|---|---|---|---|
| Upgrade to 3.11.0+ | Critical | Partially (auth still recommended) | Yes (flag defaults to False) | Indirectly (stops future leaks) |
| Enable basic-auth | High | Yes (eliminates unauthenticated path) | No (low-privilege users can still exploit) | No |
| Rotate cloud credentials | High | No | No (stops future use of leaked creds) | Yes (disables poisoned artifact access) |
| Network egress filtering | Medium | No | Yes (blocks outbound exfiltration) | Indirectly |
| Audit model artifacts | Medium | No | No | Yes (detects poisoning) |
Beyond upgrading, organizations should:
- Rotate cloud artifact credentials immediately, particularly the
AWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEYvalues present in the MLflow server environment, since they could have been exfiltrated before patching. - Audit stored model artifacts, especially
python_model.pklfiles, for signs of tampering. - Restrict the MLflow server's outbound connectivity with network egress filtering, which can block the exfiltration channel even while the vulnerability is present.
- Review existing gateway secrets for any
api_keyvalues beginning with$, which would indicate potential exploitation attempts or misconfigurations. - Verify that
MLFLOW_GATEWAY_RESOLVE_API_KEY_FROM_ENVis not set toTrueon patched versions unless there is a documented operational requirement.
Affected Systems and Versions
All MLflow versions prior to 3.11.0 with AI Gateway APIs enabled are affected. The vulnerability was confirmed in MLflow version 3.10.1.dev0, and the branch analyzed was master at commit dc8ef3cbbefccf7384f4e3023492aae635c5d5d0.
Severity depends on the deployment configuration:
- Default deployments without basic-auth: Fully exploitable by unauthenticated remote attackers. This is the highest-risk configuration.
- Deployments with basic-auth enabled: Exploitable by any low-privileged authenticated user, since the
CreateGatewaySecretendpoint lacks gateway secret pre-request permission validation. - Legacy YAML config gateway deployments (
mlflow gateway start): Even after upgrading to 3.11.0, these deployments remain vulnerable unless theMLFLOW_GATEWAY_RESOLVE_API_KEY_FROM_ENVflag is explicitly set toFalse, because the legacy startup path auto-enables it for backward compatibility.
The fix is included in MLflow version 3.11.0 and later.
Vendor Security History
MLflow has accumulated a notable number of security vulnerabilities over its development history. The pattern suggests systemic gaps in input validation and access control:
| CVE | Type | Severity | Key Detail |
|---|---|---|---|
| CVE-2026-4035 | Env variable exfiltration | 9.1 (Critical) | AI Gateway $ENV_VAR resolution in secrets |
| CVE-2026-2635 | Authentication bypass | Critical | Hard-coded default credentials in basic_auth |
| CVE-2026-2734 | Information disclosure | N/A | SearchModelVersions lacks access control |
| CVE-2026-2611 | Origin validation bypass | N/A | Improper origin validation in /ajax-api endpoints |
| CVE-2026-2651 | Insufficient access control | N/A | Exploitable when serve-artifacts enabled |
| CVE-2026-2033 | Remote code execution | Critical | Tracking Server RCE |
| CVE-2025-11201 | Directory traversal RCE | Critical | Unauthenticated path traversal in model creation |
| CVE-2025-1474 | Weak password requirements | N/A | Admin can create users without passwords |
| CVE-2024-2928 | Local file inclusion | N/A | URI fragment manipulation |
| CVE-2023-6831 | SSRF | Critical | Unauthenticated model registration |
| CVE-2023-6018 | Arbitrary file write | N/A | Artifact handling path traversal |
| CVE-2023-1177 | Path traversal | N/A | Static file serving |
The Snyk vulnerability database reports 2 critical and 9 high issues for the current version (3.12.0), and the package has a health score of 67/100 with only 1 maintainer listed. The project has 1,514 open issues and 557 open PRs on GitHub.
The fix for CVE-2026-4035 copies the hardening applied earlier to file-based API key resolution (MLFLOW_GATEWAY_RESOLVE_API_KEY_FROM_FILE), which mitigated similar path traversal risks found in CVE-2025-11201. The same class of vulnerability keeps getting fixed one code path at a time instead of through a comprehensive audit. The vendor participates in coordinated disclosure programs and typically responds with timely patches, but the frequency and similarity of these vulnerabilities indicate that security is not being addressed as a whole at the architecture level.
A separate campaign documented in GitHub issue #23500 identified 238 MLflow instances exposed on the internet with unauthenticated HTTP 200 responses. Of those, 103 (approximately 55.1%) showed confirmed indicators of compromise, including DNS callback payloads to dnsg.cc, Interactsh SSRF probes, and path traversal attempts. The attacker infrastructure was traced to IP address 205.237.106.117 (ESTOXY OU, AS3920, Paris), which is listed on the Spamhaus CBL blacklist. MLflow servers are being actively and systematically targeted in the wild, so the large exposed attack surface is a concrete risk for CVE-2026-4035.
References
- NVD: CVE-2026-4035
- Huntr Advisory: CVE-2026-4035
- GitHub Commit: Gate env-var API key resolution behind MLFLOW_GATEWAY_RESOLVE_API_KEY_FROM_ENV
- GitHub Pull Request #21544
- MLflow Environment Variables Documentation
- Snyk: MLflow Package Security
- GitHub Issue #23500: Mass SSRF via Unauthenticated Model Registration API
- Zeropath: MLflow Tracking Server CVE-2025-11201
- Databricks: Introducing MLflow
- MLflow AI Gateway Blog Post
- NVD: CVE-2026-2635
- NVD: CVE-2026-2734
- NVD: CVE-2026-2611
- Red Hat: CVE-2026-2651



