ZeroPath at Black Hat USA 2026

MLflow AI Gateway CVE-2026-4035: Brief Summary of Critical Environment Variable Exfiltration via Gateway Secrets

A brief summary of CVE-2026-4035, a critical (CVSS 9.1) credential exfiltration vulnerability in MLflow AI Gateway that allows attackers to resolve server-side environment variables and transmit them to attacker-controlled endpoints. Includes patch details and mitigation guidance.

CVE Analysis

10 min read

ZeroPath CVE Analysis
ZeroPath CVE Analysis

2026-06-03

MLflow AI Gateway CVE-2026-4035: Brief Summary of Critical Environment Variable Exfiltration via Gateway Secrets
Experimental AI-Generated Content

This CVE analysis is an experimental publication that is completely AI-generated. The content may contain errors or inaccuracies and is subject to change as more information becomes available. We are continuously refining our process.

If you have feedback, questions, or notice any errors, please reach out to us.

[email protected]

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.

MitigationPriorityAddresses Unauthenticated PathAddresses Env Var ExfiltrationAddresses Credential Escalation
Upgrade to 3.11.0+CriticalPartially (auth still recommended)Yes (flag defaults to False)Indirectly (stops future leaks)
Enable basic-authHighYes (eliminates unauthenticated path)No (low privilege users can still exploit)No
Rotate cloud credentialsHighNoNo (stops future use of leaked creds)Yes (disables poisoned artifact access)
Network egress filteringMediumNoYes (blocks outbound exfiltration)Indirectly
Audit model artifactsMediumNoNoYes (detects poisoning)

Beyond upgrading, organizations should:

  1. Rotate cloud artifact credentials immediately, particularly AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY values present in the MLflow server environment, as they could have been exfiltrated prior to patching.
  2. Audit stored model artifacts (particularly python_model.pkl files) for signs of tampering.
  3. Restrict MLflow server outbound connectivity through network egress filtering, which can block the exfiltration channel even if the vulnerability is present.
  4. Review existing gateway secrets for any api_key values beginning with $, which would indicate potential exploitation attempts or misconfigurations.
  5. Verify MLFLOW_GATEWAY_RESOLVE_API_KEY_FROM_ENV is not set to True on 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 CreateGatewaySecret endpoint 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 the MLFLOW_GATEWAY_RESOLVE_API_KEY_FROM_ENV flag is explicitly set to False, 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:

CVETypeSeverityKey Detail
CVE-2026-4035Env variable exfiltration9.1 (Critical)AI Gateway $ENV_VAR resolution in secrets
CVE-2026-2635Authentication bypassCriticalHard coded default credentials in basic_auth
CVE-2026-2734Information disclosureN/ASearchModelVersions lacks access control
CVE-2026-2611Origin validation bypassN/AImproper origin validation in /ajax-api endpoints
CVE-2026-2651Insufficient access controlN/AExploitable when serve-artifacts enabled
CVE-2026-2033Remote code executionCriticalTracking Server RCE
CVE-2025-11201Directory traversal RCECriticalUnauthenticated path traversal in model creation
CVE-2025-1474Weak password requirementsN/AAdmin can create users without passwords
CVE-2024-2928Local file inclusionN/AURI fragment manipulation
CVE-2023-6831SSRFCriticalUnauthenticated model registration
CVE-2023-6018Arbitrary file writeN/AArtifact handling path traversal
CVE-2023-1177Path traversalN/AStatic 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

Detect & fix
what others miss

Works with
  • GitHub
  • GitLab
  • Bitbucket
  • Azure DevOps Services
  • Jira
  • Linear
  • Slack
  • Security Compass
Security magnifying glass visualization