Every CVE Search/ Get API key

CVE-2026-114136

Django REST framework: JSONParser applies an attacker-named codec to the request stream

7.5 HighFix available

Django REST framework is a toolkit for building Web APIs. From 3.6.4 until 3.18.2, JSONParser.parse in rest_framework/parsers.py uses the client-supplied Content-Type charset value with codecs.getreader, which accepts byte-transform codecs such as bz2_codec rather than only text encodings. A remote unauthenticated client can therefore cause a compressed JSON request body to be expanded after Django has enforced DATA_UPLOAD_MAX_MEMORY_SIZE against only the wire bytes, allowing a very small request to consume substantial per-worker memory. The default parser set is sufficient, and any reachable endpoint that accepts a JSON body is affected. This issue is fixed in version 3.18.2.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
None
Integrity
None
Availability
High

Exploit likelihood

0.50%Up 0.2 points since Oct 22, 2026
90%50%10%1%

What each source reports

CVE List Score used 7.5

Django REST framework: JSONParser applies an attacker-named codec to the request stream

Django REST framework is a toolkit for building Web APIs. From 3.6.4 until 3.18.2, JSONParser.parse in rest_framework/parsers.py uses the client-supplied Content-Type charset value with codecs.getreader, which accepts byte-transform codecs such as bz2_codec rather than only text encodings. A remote unauthenticated client can therefore cause a compressed JSON request body to be expanded after Django has enforced DATA_UPLOAD_MAX_MEMORY_SIZE against only the wire bytes, allowing a very small request to consume substantial per-worker memory. The default parser set is sufficient, and any reachable endpoint that accepts a JSON body is affected. This issue is fixed in version 3.18.2.

Record
CVE-2026-114136
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-409, CWE-770
Updated
2026-11-02
EUVDEUVD-2026-107546 7.5

Django REST framework is a toolkit for building Web APIs. From 3.6.4 until 3.18.2, JSONParser.parse in rest_framework/parsers.py uses the client-supplied Content-Type charset value with codecs.getreader, which accepts byte-transform codecs such as bz2_codec rather than only text encodings. A remote unauthenticated client can therefore cause a compressed JSON request body to be expanded after Django has enforced DATA_UPLOAD_MAX_MEMORY_SIZE against only the wire bytes, allowing a very small request to consume substantial per-worker memory. The default parser set is sufficient, and any reachable endpoint that accepts a JSON body is affected. This issue is fixed in version 3.18.2.

Record
EUVD-2026-107546
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Updated
2026-11-02
GitHub AdvisoriesGHSA-3547-9m27-7rxg 7.5

Django REST framework: JSONParser applies an attacker-named codec to the request stream

Summary

An unauthenticated attacker can defeat Django's DATA_UPLOAD_MAX_MEMORY_SIZE limit and force a worker process to allocate arbitrary memory, by naming a compression codec in the Content-Type charset parameter. A 108-byte request body produces a 50,331,648-character value inside the view, an amplification factor of 466,033, and grows process peak RSS by about 97 MiB. No application configuration is required beyond DRF's default parser set; the endpoint only has to accept a JSON body.

Details

JSONParser.parse decodes the request body with the charset the client supplied on the Content-Type header:

# rest_framework/parsers.py
encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
try:
    decoded_stream = codecs.getreader(encoding)(stream)
    parse_constant = json.strict_constant if self.strict else None
    return json.load(decoded_stream, parse_constant=parse_constant)
except ValueError as exc:
    raise ParseError('JSON parse error - %s' % str(exc))

Of the roughly 455 codec names codecs.lookup resolves on CPython 3.14, about 18 are byte transforms instead of character sets: bz2_codec, zlib_codec, base64_codec, hex_codec, quopri_codec, uu_codec and similar. codecs.getreader is the only entry point in the codecs module that does not consult CodecInfo._is_text_encoding, so it accepts all of them. Sending Content-Type: application/json; charset=bz2_codec wraps the request stream in a bz2 decompressor before json.load reads it.

The ordering is what makes this exploitable. Django charges DATA_UPLOAD_MAX_MEMORY_SIZE against the bytes that arrived on the wire: rest_framework/request.py hands JSONParser an io.BytesIO(self.body), and HttpRequest.body is where _check_data_too_big() runs. Decompression happens afterwards, inside the parser, where nothing is counting.

This is DRF's defect and not Django's. Django resolves the charset parameter and assigns request.encoding, and codecs.lookup does resolve byte transforms, but every Django consumer of request.encoding goes through the text-codec API and fails closed. Both bytes.decode('bz2_codec') and str(raw, 'bz2_codec') raise LookupError: 'bz2_codec' is not a text encoding; use codecs.decode() to handle arbitrary codecs. DRF is the only caller that hands the request stream to codecs.getreader.

FormParser (parsers.py:84) and MultiPartParser (parsers.py:104-118) take the same client-named encoding but fail closed instead of amplifying.

The sink was introduced by 9a228116 (PR #5147, 2017-05-24, "Improve memory footprint when reading large JSON requests"), first released in 3.6.4. The final comment on that PR observes the intended memory gain does not hold because read() decodes the whole stream, which is the same property that makes this expansion unbounded. No _is_text_encoding check has been added since.

A one-line fix at parsers.py:61-64:

if not codecs.lookup(encoding)._is_text_encoding:
    raise ParseError('Unsupported charset in Content-Type')

PoC

Save as poc_charset_amplification.py and run it. It builds its own payloads, runs each arm in a fresh subprocess (peak RSS is a high-water mark, so measuring several arms in one process reports near-zero growth for every arm after the first), and prints a verdict.

#!/usr/bin/env python
"""
django-rest-framework: JSONParser applies an attacker-named codec to the request
stream, defeating DATA_UPLOAD_MAX_MEMORY_SIZE.

Four arms, each in a fresh subprocess because peak RSS is a high-water mark and
measuring several arms in one process reports ~0 growth for every arm after the
first.

  T   ~108-byte bz2 body, Content-Type: application/json; charset=bz2_codec
  C1  48 MiB plaintext,   Content-Type: application/json   (no charset)
  C2  the byte-identical T body, charset=utf-8
  C3  zlib body, charset=zlib_codec

The claim is T AND C1 AND C2. C1 proves the size limit is live; C2 proves the…
Record
GHSA-3547-9m27-7rxg
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-409, CWE-770
Updated
2026-11-02
NVD 7.5

Django REST framework is a toolkit for building Web APIs. From 3.6.4 until 3.18.2, JSONParser.parse in rest_framework/parsers.py uses the client-supplied Content-Type charset value with codecs.getreader, which accepts byte-transform codecs such as bz2_codec rather than only text encodings. A remote unauthenticated client can therefore cause a compressed JSON request body to be expanded after Django has enforced DATA_UPLOAD_MAX_MEMORY_SIZE against only the wire bytes, allowing a very small request to consume substantial per-worker memory. The default parser set is sufficient, and any reachable endpoint that accepts a JSON body is affected. This issue is fixed in version 3.18.2.

Record
CVE-2026-114136
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-409, CWE-770
Updated
2026-11-02
OSV 7.5

Django REST framework: JSONParser applies an attacker-named codec to the request stream

Django REST framework is a toolkit for building Web APIs. From 3.6.4 until 3.18.2, JSONParser.parse in rest_framework/parsers.py uses the client-supplied Content-Type charset value with codecs.getreader, which accepts byte-transform codecs such as bz2_codec rather than only text encodings. A remote unauthenticated client can therefore cause a compressed JSON request body to be expanded after Django has enforced DATA_UPLOAD_MAX_MEMORY_SIZE against only the wire bytes, allowing a very small request to consume substantial per-worker memory. The default parser set is sufficient, and any reachable endpoint that accepts a JSON body is affected. This issue is fixed in version 3.18.2.

Record
CVE-2026-114136
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-409, CWE-770
Updated
2026-11-02
OSVDEBIAN-CVE-2026-114136 7.5

Django REST framework is a toolkit for building Web APIs. From 3.6.4 until 3.18.2, JSONParser.parse in rest_framework/parsers.py uses the client-supplied Content-Type charset value with codecs.getreader, which accepts byte-transform codecs such as bz2_codec rather than only text encodings. A remote unauthenticated client can therefore cause a compressed JSON request body to be expanded after Django has enforced DATA_UPLOAD_MAX_MEMORY_SIZE against only the wire bytes, allowing a very small request to consume substantial per-worker memory. The default parser set is sufficient, and any reachable endpoint that accepts a JSON body is affected. This issue is fixed in version 3.18.2.

Record
DEBIAN-CVE-2026-114136
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Updated
2026-11-02
Show 4 moreShow less
OSVGHSA-3547-9m27-7rxg 7.5

Django REST framework: JSONParser applies an attacker-named codec to the request stream

Summary

An unauthenticated attacker can defeat Django's DATA_UPLOAD_MAX_MEMORY_SIZE limit and force a worker process to allocate arbitrary memory, by naming a compression codec in the Content-Type charset parameter. A 108-byte request body produces a 50,331,648-character value inside the view, an amplification factor of 466,033, and grows process peak RSS by about 97 MiB. No application configuration is required beyond DRF's default parser set; the endpoint only has to accept a JSON body.

Details

JSONParser.parse decodes the request body with the charset the client supplied on the Content-Type header:

# rest_framework/parsers.py
encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
try:
    decoded_stream = codecs.getreader(encoding)(stream)
    parse_constant = json.strict_constant if self.strict else None
    return json.load(decoded_stream, parse_constant=parse_constant)
except ValueError as exc:
    raise ParseError('JSON parse error - %s' % str(exc))

Of the roughly 455 codec names codecs.lookup resolves on CPython 3.14, about 18 are byte transforms instead of character sets: bz2_codec, zlib_codec, base64_codec, hex_codec, quopri_codec, uu_codec and similar. codecs.getreader is the only entry point in the codecs module that does not consult CodecInfo._is_text_encoding, so it accepts all of them. Sending Content-Type: application/json; charset=bz2_codec wraps the request stream in a bz2 decompressor before json.load reads it.

The ordering is what makes this exploitable. Django charges DATA_UPLOAD_MAX_MEMORY_SIZE against the bytes that arrived on the wire: rest_framework/request.py hands JSONParser an io.BytesIO(self.body), and HttpRequest.body is where _check_data_too_big() runs. Decompression happens afterwards, inside the parser, where nothing is counting.

This is DRF's defect and not Django's. Django resolves the charset parameter and assigns request.encoding, and codecs.lookup does resolve byte transforms, but every Django consumer of request.encoding goes through the text-codec API and fails closed. Both bytes.decode('bz2_codec') and str(raw, 'bz2_codec') raise LookupError: 'bz2_codec' is not a text encoding; use codecs.decode() to handle arbitrary codecs. DRF is the only caller that hands the request stream to codecs.getreader.

FormParser (parsers.py:84) and MultiPartParser (parsers.py:104-118) take the same client-named encoding but fail closed instead of amplifying.

The sink was introduced by 9a228116 (PR #5147, 2017-05-24, "Improve memory footprint when reading large JSON requests"), first released in 3.6.4. The final comment on that PR observes the intended memory gain does not hold because read() decodes the whole stream, which is the same property that makes this expansion unbounded. No _is_text_encoding check has been added since.

A one-line fix at parsers.py:61-64:

if not codecs.lookup(encoding)._is_text_encoding:
    raise ParseError('Unsupported charset in Content-Type')

PoC

Save as poc_charset_amplification.py and run it. It builds its own payloads, runs each arm in a fresh subprocess (peak RSS is a high-water mark, so measuring several arms in one process reports near-zero growth for every arm after the first), and prints a verdict.

#!/usr/bin/env python
"""
django-rest-framework: JSONParser applies an attacker-named codec to the request
stream, defeating DATA_UPLOAD_MAX_MEMORY_SIZE.

Four arms, each in a fresh subprocess because peak RSS is a high-water mark and
measuring several arms in one process reports ~0 growth for every arm after the
first.

  T   ~108-byte bz2 body, Content-Type: application/json; charset=bz2_codec
  C1  48 MiB plaintext,   Content-Type: application/json   (no charset)
  C2  the byte-identical T body, charset=utf-8
  C3  zlib body, charset=zlib_codec

The claim is T AND C1 AND C2. C1 proves the size limit is live; C2 proves the…
Record
GHSA-3547-9m27-7rxg
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-409, CWE-770
Updated
2026-11-02
OSVUBUNTU-CVE-2026-114136 7.5

Django REST framework is a toolkit for building Web APIs. From 3.6.4 until 3.18.2, JSONParser.parse in rest_framework/parsers.py uses the client-supplied Content-Type charset value with codecs.getreader, which accepts byte-transform codecs such as bz2_codec rather than only text encodings. A remote unauthenticated client can therefore cause a compressed JSON request body to be expanded after Django has enforced DATA_UPLOAD_MAX_MEMORY_SIZE against only the wire bytes, allowing a very small request to consume substantial per-worker memory. The default parser set is sufficient, and any reachable endpoint that accepts a JSON body is affected. This issue is fixed in version 3.18.2.

Record
UBUNTU-CVE-2026-114136
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Updated
2026-11-02
OSVopenSUSE-SU-2026:12277-1 No score

python313-djangorestframework-3.18.2-1.1 on GA media

These are all security issues fixed in the python313-djangorestframework-3.18.2-1.1 package on the GA media of openSUSE Tumbleweed.

Record
openSUSE-SU-2026:12277-1
Updated
2026-11-02
OSVROOT-APP-PYPI-CVE-2026-114136 No score

CVE-2026-114136 in djangorestframework - Patched by Root

Root has patched CVE-2026-114136 in the djangorestframework package for Root:PyPI. Multiple fixed versions available.

Record
ROOT-APP-PYPI-CVE-2026-114136
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
djangorestframework
PyPI
3.6.4 up to 3.18.2
3.18.2
djangorestframework
Debian:12
All versions, plus listed versions
3.14.0-23.14.0-2+deb12u13.15.1-13.15.1-23.15.2-1
Show 9 moreShow less
3.15.2-23.16.0-13.16.1-13.16.1-33.16.1-43.17.1+ds1-13.17.1-13.18.1+ds1-13.18.3+ds1-1
None known
djangorestframework
Debian:13
All versions, plus listed versions
3.16.0-13.16.1-13.16.1-33.16.1-43.17.1+ds1-13.17.1-13.18.1+ds1-13.18.3+ds1-1
None known
djangorestframework
Debian:14
before 3.18.3+ds1-1, plus listed versions
3.16.0-13.16.1-13.16.1-33.16.1-43.17.1+ds1-13.17.1-13.18.1+ds1-1
3.18.3+ds1-1
djangorestframework
PyPI
3.6.4 up to 3.18.2, plus listed versions
3.10.03.10.13.10.23.10.33.11.0
Show 36 moreShow less
3.11.13.11.23.12.03.12.13.12.23.12.33.12.43.13.03.13.13.14.03.15.03.15.13.15.23.16.03.16.13.17.03.17.13.17.23.18.03.18.13.7.03.7.13.7.23.7.33.7.43.7.53.7.63.7.73.8.03.8.13.8.23.9.03.9.13.9.23.9.33.9.4
3.18.2
djangorestframework
Root:PyPI
before 3.12.4+aikido.2
3.12.4+aikido.23.16.1+aikido.13.17.2+aikido.13.15.1+aikido.13.14.0+aikido.2
djangorestframework
Ubuntu:16.04:LTS
All versions, plus listed versions
2.4.3-23.3.1-13.3.2-13.3.2-2
None known
djangorestframework
Ubuntu:18.04:LTS
All versions, plus listed versions
3.4.0-23.7.7-1
None known
djangorestframework
Ubuntu:20.04:LTS
All versions, plus listed versions
3.9.0-23.10.2-1
None known
djangorestframework
Ubuntu:22.04:LTS
All versions, plus listed versions
3.12.1-13.12.4-13.12.4-23.12.4-2ubuntu13.12.4-2.1ubuntu1
None known
Show 4 moreShow less
Affected packages
PackageAffectedFixed
djangorestframework
Ubuntu:24.04:LTS
All versions, plus listed versions
3.14.0-2
None known
djangorestframework
Ubuntu:26.10
All versions, plus listed versions
3.16.1-33.16.1-43.17.1+ds1-1
None known
djangorestframework
Ubuntu:26.04:LTS
All versions, plus listed versions
3.16.1-13.16.1-3
None known
python-djangorestframework
openSUSE:Tumbleweed
From an advisory covering 3 CVEs
before 3.18.2-1.1
3.18.2-1.1

History

History
RecordedChangedSources
affected, facts
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-114136 is a high vulnerability (CVSS 7.5) in Encode Django-rest-framework, published October 21, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.50%, the 43rd percentile. Fixed in djangorestframework 3.18.2.

References

Show 7 moreShow less
This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open