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), allows any user (or in default deployments, any unauthenticated network client) to 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, created by Databricks in 2018 for managing the complete machine learning lifecycle. With 26.2k GitHub stars and 5.8k forks, it serves as foundational infrastructure for ML teams across industries. The MLOps market it anchors is projected to reach approximately $4.39 billion in 2026, making vulnerabilities in MLflow's core services a concern that extends well beyond individual deployments.
The real danger here is not just the credential leak itself. Demonstrated exploitation scenarios show that exfiltrated AWS credentials can be leveraged to poison model artifacts in S3, and when downstream consumers load those poisoned models, malicious cloudpickle payloads execute arbitrary code in their environments. This transforms a credential disclosure vulnerability into 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 root cause lies 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. The resolved secret value was then transmitted 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, meaning the resolved secret could be directed to any network endpoint.
Attack Flow
The exploitation chain is straightforward and requires only access to the MLflow REST API:
Step 1: Store a Malicious Secret. The attacker creates a gateway secret containing $TARGET_ENV as the api_key value, where TARGET_ENV is the name of the environment variable to exfiltrate. For example, {"api_key": "$AWS_SECRET_ACCESS_KEY"}.
Step 2: Configure an Attacker Controlled Endpoint. The attacker sets the api_base parameter to point to a service under their control. This is the capture server that will receive the leaked credentials when the gateway makes outbound requests.
Step 3: Trigger Invocation. The attacker invokes the gateway endpoint (for example, /gateway/openai/v1/chat/completions), causing the server to resolve the environment variable at runtime and send 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. Given that a separate scanning campaign identified 238 MLflow instances exposed on the internet with unauthenticated HTTP 200 responses on port 5000, this is not a theoretical concern.
In basic-auth deployments, low privileged authenticated users can still exploit the vulnerability. The CreateGatewaySecret endpoint is not covered by gateway secret pre-request permission validators, and creators are automatically granted manage/use permissions on their resources. This means any user who can authenticate to the MLflow instance can create the malicious gateway secret configuration.
Escalation to Supply Chain Attack
The most severe demonstrated impact goes beyond simple credential theft. Leaked AWS credentials (AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY) from the MLflow server environment can be used to overwrite model artifacts in S3. Specifically, an attacker can replace python_model.pkl files with malicious cloudpickle payloads. When downstream consumers load the poisoned model, the malicious code executes in their environment, creating a cross boundary remote code execution scenario. This transforms a single credential leak into a supply chain compromise affecting 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 confirms the status as Fixed, with CWE-201 classification and a CVSS 3.1 score of 9.1 (Critical).
The fix introduces a new opt-in boolean flag called MLFLOW_GATEWAY_RESOLVE_API_KEY_FROM_ENV, which defaults to False. This mirrors an existing pattern already used for file based key resolution (MLFLOW_GATEWAY_RESOLVE_API_KEY_FROM_FILE). The critical 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:]
With this change, unless the flag is explicitly enabled, any $ prefixed value is treated as a literal string and returned as is. The string $MY_SECRET would simply become the literal API key string $MY_SECRET rather than being resolved to the contents of the MY_SECRET environment variable.
The flag definition is added in mlflow/environment_variables.py:
MLFLOW_GATEWAY_RESOLVE_API_KEY_FROM_ENV = _BooleanEnvironmentVariable( "MLFLOW_GATEWAY_RESOLVE_API_KEY_FROM_ENV", False )
Backward compatibility for the legacy YAML config gateway (mlflow gateway start) is preserved. Both mlflow/gateway/app.py and mlflow/gateway/runner.py were updated to auto enable this flag when starting in legacy mode:
os.environ[MLFLOW_GATEWAY_RESOLVE_API_KEY_FROM_ENV.name] = "true"
This means the modern API driven gateway (the primary attack surface for this vulnerability) is protected by default, while the legacy YAML config gateway, where environment variable resolution is a documented and expected feature, retains its existing behavior.
The commit also includes a dedicated test (test_api_key_env_resolution_blocked_without_flag) that explicitly validates the new security boundary, asserting 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: a compact, well scoped fix that addresses the vulnerability through a secure by default design principle.
Important caveat for operators: Organizations using the legacy YAML config gateway invoked via mlflow gateway start should be aware that the patch automatically sets the flag to "true" in that code path, preserving the vulnerable behavior for backward compatibility. If environment variable resolution in gateway secrets is not required, operators 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
AWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEYvalues present in the MLflow server environment, as they could have been exfiltrated prior to patching. - Audit stored model artifacts (particularly
python_model.pklfiles) for signs of tampering. - Restrict MLflow server outbound connectivity through network egress filtering, which can block the exfiltration channel even if the vulnerability is present.
- Review existing gateway secrets for any
api_keyvalues beginning with$, which would indicate potential exploitation attempts or misconfigurations. - Verify
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 target branch at analysis was master at commit dc8ef3cbbefccf7384f4e3023492aae635c5d5d0.
Specific deployment configurations affect the severity:
- 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 across its development history, suggesting 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 mirrors the hardening pattern previously applied to file based API key resolution (MLFLOW_GATEWAY_RESOLVE_API_KEY_FROM_FILE), which mitigated similar path traversal risks found in CVE-2025-11201. This reactive pattern, where the same class of vulnerability is addressed incrementally rather than through a comprehensive audit, is a recurring theme. While the vendor does participate in coordinated disclosure programs and typically responds with timely patches, the frequency and similarity of these vulnerabilities indicates that security is not being addressed holistically 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 which 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), listed on the Spamhaus CBL blacklist. This demonstrates that MLflow servers are being actively and systematically targeted in the wild, making the large exposed attack surface a concrete rather than theoretical 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



