Django REST framework: unauthenticated CPU-exhaustion DoS via crafted Accept header and silent token revocation failure (CVE-2026-114138, CVE-2026-114137)
Severity: high · Patch status: patched · Since 2026-10-06 · CVE-2026-114137, CVE-2026-114138
Two high-severity advisories were published for Django REST framework, both fixed in 3.18.2. CVE-2026-114138: DRF's content negotiation parses each Accept token up to six times per request with no cap on token count or size, and Django's parseheaderparameters is quadratic on semicolon-packed quoted values; a single unauthenticated GET with a 780KB Accept header (96 tokens under gunicorn's default limits) burns ~19s of CPU per worker, and two concurrent requests can wedge a default two-worker deployment for the duration of the attack. CVE-2026-114137: TokenProxy.delete() builds its delete query from a pk property returning the user id, matching it against the 40-char key column, so token revocation via .delete() silently deletes nothing while reporting success — revoked tokens keep authenticating. Both issues have public PoCs; no in-the-wild exploitation is known. Fix: upgrade to djangorestframework 3.18.2.
What to do
- Upgrade djangorestframework to 3.18.2 or later immediately
- If you cannot upgrade, add reverse-proxy/WAF limits on Accept header size and number of Accept request fields (e.g. cap total ~8KB / 64 tokens) to mitigate the DoS
- Audit any code, admin integrations or scripts that revoke auth tokens via TokenProxy.delete(); replace with Token.objects.get(key=...).delete() and verify revocation by checking the row is gone and the token returns 401
- Review whether token revocation failures could have left credentials live (e.g. offboarded users or leaked tokens assumed revoked) and rotate those tokens
- Monitor for slow requests with unusually large Accept headers as an exploitation indicator
Fixed versions
- djangorestframework 3.18.2
Sources
All live incidents on Threat Watch