CVE-2026-114138
### Summary DRF's content negotiation parses each Accept token several times per request and never limits the number of tokens or their total size. Each parse ends up in Django's parse_header_parameters, which takes quadratic time when a quoted parameter value is packed with semicolons. On my machine a single GET with a 780KB Accept header made of 96 such tokens kept one gunicorn worker busy for 18.87 seconds (Django 6.1, djangorestframework 3.18.0, gunicorn 26.0.0, Python 3.13, Docker on macOS). The header is syntactically valid, fits inside gunicorn's default header limits, and needs no authentication. Two concurrent requests, which is one per sync worker, made a default two worker deployment stop answering for my whole 40 second test window. It recovered half a second after I stopped sending. ### Details #### What happens get_accept_list() splits the Accept header on commas with no cap on token count or total size, at rest_framework/negotiation.py:96-97. For every token, select_renderer() calls media_type_matches() once per renderer, and each call builds fresh _MediaType objects for both sides, at rest_framework/negotiation.py:53-56 and rest_framework/utils/mediatypes.py:22-23. `_MediaType.__init__` calls django.utils.http.parse_header_parameters unconditionally, at rest_framework/utils/mediatypes.py:47. When nothing matches, DRF raises NotAcceptable (406). Rendering that error response also needs a renderer, so finalize_response() runs the entire negotiation a second time through perform_content_negotiation(force=True), at rest_framework/views.py:434-437. With the default two renderers this comes to about six parses per Accept token per request. I confirmed the count by instrumenting _MediaType with a counter: six per token, three from the normal pass and three from the forced re-negotiation. The quadratic part is on the Django side. parse_header_parameters splits parameters with _parseparam, which handles quoted values by recounting the quote character
Properties
- Severity
- high
- Summary
- Django REST framework: Accept header with many large quoted parameters burns ~19s of CPU per request in content negotiation
- Nvd fetched at
- 2026-10-22T22:14:18.200859+00:00
- Epss score
- 0.00432
- Cvss severity
- HIGH
- Cvss score
- 7.5
- Retrieved at
- 2026-10-22T22:17:33+00:00
- Ghsa published
- 2026-10-22T16:17:13Z
- Source url
- https://github.com/advisories/GHSA-33wh-fxxf-88vv
- Ghsa updated
- 2026-10-22T16:17:15Z
- Ghsa id
- GHSA-33wh-fxxf-88vv
- Last source
- FIRST EPSS
- Score
- 7.5
- Cvss version
- 3.1
- Cve id
- CVE-2026-114138
- Cvss vector
- CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
- First seen by Signal
- 2026-10-21T22:34:38+00:00
- Is ghsa only
- false
- Vector
- CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
- Published at
- 2026-10-21T21:17:56.200
Related Entities (4)
HAS_WEAKNESS (2)
AFFECTS (1)
VULNERABLE_TO (1)
Explore deeper with Ninja Signal's threat intelligence graph