Skip to content

chore(deps): update dependency djangorestframework to v3.17.2 [security] - #1426

Open
renovate[bot] wants to merge 1 commit into
masterfrom
renovate/pypi-djangorestframework-vulnerability
Open

chore(deps): update dependency djangorestframework to v3.17.2 [security]#1426
renovate[bot] wants to merge 1 commit into
masterfrom
renovate/pypi-djangorestframework-vulnerability

Conversation

@renovate

@renovate renovate Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

ℹ️ Note

This PR body was truncated due to platform limits.

This PR contains the following updates:

Package Change Age Confidence
djangorestframework (changelog) ==3.12.4==3.17.2 age confidence

Cross-site Scripting in djangorestframework

CVE-2024-21520 / GHSA-gw84-84pc-xp82

More information

Details

Versions of the package djangorestframework before 3.15.2 are vulnerable to Cross-site Scripting (XSS) via the break_long_headers template filter due to improper input sanitization before splitting and joining with
tags.

Severity

  • CVSS Score: 2.1 / 10 (Low)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:L/VA:N/SC:L/SI:L/SA:N/E:P

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Django REST framework: Potential bypass of Django DATA_UPLOAD_MAX_MEMORY_SIZE when parsing oversized JSON and urlencoded request bodies via DRF request.data

CVE-2026-73228 / GHSA-2m8g-3cmr-wg3w

More information

Details

Summary

While investigating Django REST Framework's request parsing behavior, I identified that DRF's high-level request.data parsing appears to bypass Django's configured DATA_UPLOAD_MAX_MEMORY_SIZE protection for application/json and application/x-www-form-urlencoded request bodies.

In the tested configurations, Django correctly raises RequestDataTooBig when applications access request.body or Django's native request.POST, but DRF successfully parses the same oversized payloads through request.data.

This behavior appears to occur because DRF passes the underlying HttpRequest object directly to parsers, which consume the request stream through Django's lower-level streaming interface rather than the guarded request.body path.

I am reporting this privately because I am unsure whether this behavior is considered part of DRF's intended security boundary, but it appears to bypass a documented Django request-size protection for common DRF request parsing paths and may have availability implications.

What I Verified

I verified the behavior locally using the following combinations:

  • Django 6.0.7 + DRF 3.17.1Affected
  • Django 6.0.7 + DRF current upstream mainAffected

For both versions, the observed behavior was:

Django request.body
→ RequestDataTooBig

Django request.POST (application/x-www-form-urlencoded)
→ RequestDataTooBig

Django request.read()
→ Reads the entire oversized request body

DRF request.data
→ Successfully parses oversized JSON and urlencoded request bodies

I also confirmed that:

  • multipart/form-data remains protected because DRF delegates multipart parsing to Django's multipart parser.
  • The behavior reproduces on both direct WSGI and ASGI servers without a reverse proxy or external request-size middleware.
Technical Details

The relevant execution flow is:

APIView

↓

rest_framework.request.Request

↓

request.data

↓

Request._load_data_and_files()

↓

Request._parse()

↓

Request._load_stream()

↓

self._stream = self._request

↓

JSONParser.parse(...)
or
FormParser.parse(...)

↓

stream.read() / json.load(...)

The important implementation detail is that DRF assigns the original Django HttpRequest object as the parser stream.

Unlike request.body and Django's native form parsing, consuming the stream through HttpRequest.read() does not trigger Django's RequestDataTooBig protection.

As a result, DRF's built-in parsers successfully consume oversized request bodies that Django itself would reject through its higher-level request interfaces.

Reproduction Steps
Environment

Python 3.13

Django 6.0.7

Django REST Framework 3.17.1 (also reproduced on current upstream main)

Configure:

DATA_UPLOAD_MAX_MEMORY_SIZE = 10

Create a simple DRF API view:

from rest_framework.views import APIView
from rest_framework.response import Response

class DemoView(APIView):
    def post(self, request):
        return Response(request.data)

Start the application.

Send an oversized JSON request:

POST /demo
Content-Type: application/json
Content-Length: >10 bytes

Example:

{
  "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA..."
}

Observed:

HTTP 200

JSON successfully parsed

Now compare against:

request.body

Observed:

RequestDataTooBig

Likewise, compare against:

request.POST

using

application/x-www-form-urlencoded

Observed:

RequestDataTooBig

This demonstrates different enforcement depending on which request API is used.

Root Cause

Django documents HttpRequest.read() as a streaming interface.

DRF exposes request.data as the primary high-level request parsing API.

Currently, DRF forwards the raw Django request stream directly to parsers before any request-size validation equivalent to Django's request.body path occurs.

Consequently:

  • JSONParser
  • FormParser

fully consume oversized request bodies despite Django's configured request-size limit.

Security Impact

This does not appear to introduce:

  • Authentication bypass
  • Authorization bypass
  • Remote code execution
  • Information disclosure
  • Integrity compromise

However, it may reduce the effectiveness of deployments relying on Django's DATA_UPLOAD_MAX_MEMORY_SIZE to limit request-body resource consumption.

Potential consequences include:

  • Additional memory allocation during JSON parsing
  • Additional CPU usage while decoding large JSON payloads
  • Increased resource consumption when handling oversized request bodies
  • Reduced effectiveness of Django's configured request-size protection for DRF endpoints using request.data

The practical impact depends on deployment configuration, including:

  • upstream request-size limits
  • reverse proxy configuration
  • authentication
  • rate limiting
  • endpoint exposure
Memory Observations

During local testing I observed successful parsing of oversized request bodies despite the configured limit.

Representative measurements showed significantly increased memory allocation while parsing large JSON and urlencoded payloads.

I intentionally did not perform destructive concurrency testing or attempt to exhaust system resources.

Scope

Confirmed affected:

  • application/json
  • application/x-www-form-urlencoded

Confirmed not affected:

  • multipart/form-data
Suggested Fix Direction

One possible approach would be for DRF to enforce Django's configured DATA_UPLOAD_MAX_MEMORY_SIZE before handing the raw request stream to parsers that fully materialize request bodies in memory.

This would preserve Django's configured request-size protection for the common request.data API without requiring broader changes to Django's documented streaming interface.

Versions Tested

Affected:

  • Django 6.0.7 + DRF 3.17.1
  • Django 6.0.7 + DRF current upstream main

I did not perform a complete historical version bisect.

Disclosure

I have not publicly disclosed this behavior.

I am submitting it privately in accordance with the project's security policy because I am unsure whether maintainers consider this part of DRF's intended security boundary.

Note:

Thank you for taking the time to review this report.

If you determine that this behavior should be addressed, I would be happy to help investigate further, develop a fix, add regression tests, and submit a patch if you'd find that helpful.

I have experience as a Python/Django software engineer, security researcher, and open-source contributor, and I'd be glad to contribute if you think that would be useful.

Severity

  • CVSS Score: 5.3 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Django REST framework: AdminRenderer may disclose GET-protected data when rendering invalid write requests

CVE-2026-73229 / GHSA-g47c-3xmw-q6m2

More information

Details

Summary

AdminRenderer may disclose data that would normally be protected by GET permissions when rendering a 400 Bad Request response for an invalid write request.

If a view allows POST (or another write method) but denies GET, an invalid request rendered through AdminRenderer can invoke the view's GET handler and include data from the GET representation in the generated HTML response.

This behavior appears to be specific to AdminRenderer and does not affect the normal JSON rendering path.


Details

While investigating the AdminRenderer rendering flow, I observed that invalid write requests are rendered by temporarily overriding the request method and invoking the view's GET handler:

with override_method(view, request, "GET") as request:
    response = view.get(request, *view.args, **view.kwargs)

data = response.data

This execution path differs from a normal GET request.

Under normal request processing, a GET request flows through:

APIView.dispatch()
    └── APIView.initial()
            └── APIView.check_permissions()

However, during AdminRenderer rendering, the renderer directly invokes:

view.get(...)

A view whose permission class explicitly allowed POST but denied GET still executed its GET handler while rendering an invalid POST request through AdminRenderer.

As a result, data intended to be available only through an authorized GET request was included in the generated HTML response.


Proof of Concept

Using a standard ListCreateAPIView.

Permission class:

class ProbePermission(BasePermission):
    def has_permission(self, request, view):
        return request.method == "POST"

View:

class View(ListCreateAPIView):
    renderer_classes = (AdminRenderer, JSONRenderer)
    permission_classes = (ProbePermission,)
    serializer_class = ProbeSerializer

    def get_queryset(self):
        return [
            {
                "name": "visible",
                "secret": "GET-ONLY-SECRET",
            }
        ]

Expected Behaviour

GET request
→ 403 Forbidden

Invalid POST request
→ 400 Bad Request
→ Response should contain only validation errors.
→ GET-only data should not be rendered.

Observed Behaviour

GET request
→ 403 Forbidden

Invalid POST request rendered through AdminRenderer
→ 400 Bad Request
→ HTML response contains:

GET-ONLY-SECRET

Tthe same behavior is shown using a minimal APIView implementation.

Observed results:

minimal.post_400.handler_calls =
[
    ("post", "POST"),
    ("get", "GET")
]

minimal.post_400.contains_secret = True

Generic view reproduction:

generic.direct_get.status = 403
generic.direct_get.contains_secret = False

generic.post_400.status = 400
generic.post_400.contains_secret = True

generic.post_400.permission_calls =
[
    ("GenericAdminView", "POST"),
    ...
    ("GenericAdminView", "OPTIONS")
]

generic.post_400.queryset_calls =
[
    ("GenericAdminView", "GET"),
    ...
]

These observations indicate that direct GET requests are correctly denied, while the simulated GET used during AdminRenderer rendering can still retrieve the protected representation.


Impact

This issue may result in information disclosure when all of the following conditions are met:

AdminRenderer is enabled.

The client negotiates the HTML renderer (for example using Accept: text/html).

The application permits POST (or another write method).

GET requests are denied by the configured permission class.

The invalid write request returns 400 Bad Request.

The GET representation contains information that the requester would normally not be permitted to access.

This issue does not appear to affect:

JSON rendering

Standard API responses

Successful write requests

The behavior appears limited to the HTML rendering path used by AdminRenderer.


Suggested Fix

Possible approaches include:

Perform equivalent permission checks before executing the simulated GET request.

Avoid invoking view.get() when the corresponding GET request would not be permitted.

Fall back to rendering only serializer/form validation errors instead of retrieving the GET representation.

A regression test could create a permission class that allows POST while denying GET, then verify that an invalid POST rendered with AdminRenderer does not include data from the protected GET representation.


Environment

Repository:

encode/django-rest-framework

Branch tested:

security-audit-drf

Commit tested:

cf582fb58e9e5ffcc8ed78a2cb9aaa8f4865666a

Severity

  • CVSS Score: 4.3 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Release Notes

encode/django-rest-framework (djangorestframework)

v3.17.2

Compare Source

What's Changed

Bug fixes

Full Changelog: encode/django-rest-framework@3.17.1...3.17.2

v3.17.1

Compare Source

What's Changed

Bug fixes

Full Changelog: encode/django-rest-framework@3.17.0...3.17.1

v3.17.0

Compare Source

What's Changed

Breaking changes
Features
Bug fixes
Translations
Packaging
Other changes

New Contributors

Full Changelog: encode/django-rest-framework@3.16.1...3.17.0

v3.16.1

Compare Source

This release fixes a few bugs, clean-up some old code paths for unsupported Python versions and improve translations.

Minor changes

  • Cleanup optional backports.zoneinfo dependency and conditions on unsupported Python 3.8 and lower in #​9681. Python versions prior to 3.9 were already unsupported so this isn't considered as a breaking change.

Bug fixes

  • Fix regression in unique_together validation with SerializerMethodField in #​9712
  • Fix UniqueTogetherValidator to handle fields with source attribute in #​9688
  • Drop HTML line breaks on long headers in browsable API in #​9438

Translations

  • Add Kazakh locale support in #​9713
  • Update translations for Korean translations in #​9571
  • Update German translations in #​9676
  • Update Chinese translations in #​9675
  • Update Arabic translations-sal in #​9595
  • Update Persian translations in #​9576
  • Update Spanish translations in #​9701
  • Update Turkish Translations in #​9749
  • Fix some typos in Brazilian Portuguese translations in #​9673

Documentation

  • Removed reference to GitHub Issues and Discussions in #​9660
  • Add drf-restwind and update outdated images in browsable-api.md in #​9680
  • Updated funding page to represent current scope in #​9686
  • Fix broken Heroku JSON Schema link in #​9693
  • Update Django documentation links to use stable version in #​9698
  • Expand docs on unique constraints cause 'required=True' in #​9725
  • Revert extension back from djangorestframework-guardian2 to djangorestframework-guardian in #​9734
  • Add note to tutorial about required request in serializer context when using HyperlinkedModelSerializer in #​9732

Internal changes

  • Update GitHub Actions to use Ubuntu 24.04 for testing in #​9677
  • Update test matrix to use Django 5.2 stable version in #​9679
  • Add pyupgrade to pre-commit hooks in #​9682
  • Fix test with Django 5 when pytz is available in #​9715

New Contributors

Full Changelog: encode/django-rest-framework@3.16.0...3.16.1

v3.16.0

Compare Source

This release is considered a significant release to improve upstream support with Django and Python. Some of these may change the behaviour of existing features and pre-existing behaviour. Specifically, some fixes were added to around the support of UniqueConstraint with nullable fields which will improve built-in serializer validation.

Features

  • Add official support for Django 5.1 and its new LoginRequiredMiddleware in #​9514 and #​9657
  • Add official Django 5.2a1 support in #​9634
  • Add support for Python 3.13 in #​9527 and #​9556
  • Support Django 2.1+ test client JSON data automatically serialized in #​6511 and fix a regression in #​9615

Bug fixes

  • Fix unique together validator to respect condition's fields from UniqueConstraint in #​9360
  • Fix raising on nullable fields part of UniqueConstraint in #​9531
  • Fix unique_together validation with source in #​9482
  • Added protections to AttributeError raised within properties in #​9455
  • Fix get_template_context to handle also lists in #​9467
  • Fix "Converter is already registered" deprecation warning. in #​9512
  • Fix noisy warning and accept integers as min/max values of DecimalField in #​9515
  • Fix usages of open() in setup.py in #​9661

Translations

  • Add some missing Chinese translations in #​9505
  • Fix spelling mistakes in Farsi language were corrected in #​9521
  • Fixing and adding missing Brazilian Portuguese translations in #​9535

Removals

  • Remove support for Python 3.8 in #​9670
  • Remove long deprecated code from request wrapper in #​9441
  • Remove deprecated AutoSchema._get_reference method in #​9525

Documentation and internal changes

  • Provide tests for hashing of OperandHolder in #​9437
  • Update documentation: Add adrf third party package in #​9198
  • Update tutorials links in Community contributions docs in #​9476
  • Fix usage of deprecated Django function in example from docs in #​9509
  • Move path converter docs into a separate section in #​9524
  • Add test covering update view without queryset attribute in #​9528
  • Fix Transifex link in #​9541
  • Fix example httpie call in docs in #​9543
  • Fix example for serializer field with choices in docs in #​9563
  • Remove extra <> in validators example in #​9590
  • Update strftime link in the docs in #​9624
  • Switch to codecov GHA in #​9618
  • Add note regarding availability of the action attribute in 'Introspecting ViewSet actions' docs section in #​9633
  • Improved description of allowed throttling rates in documentation in #​9640
  • Add rest-framework-gm2m-relations package to the list of 3rd party libraries in #​9063
  • Fix a number of typos in the test suite in the docs in #​9662
  • Add django-pyoidc as a third party authentication library in #​9667

New Contributors

Full Changelog: encode/django-rest-framework@3.15.2...3.16.0

v3.15.2

Compare Source

What's Changed

New Contributors

Full Changelog: encode/django-rest-framework@3.15.1...3.15.2

v3.15.1: Version 3.15.1

Compare Source

What's Changed

New Contributors

Full Changelog: encode/django-rest-framework@3.15.0...3.15.1

v3.15.0

Compare Source

v3.14.0: Version 3.14.0

Compare Source

  • Django 2.2 is no longer supported. #​8662
  • Django 4.1 compatibility. #​8591
  • Add --api-version CLI option to generateschema management command. #​8663
  • Enforce is_valid(raise_exception=False) as a keyword-only argument. #​7952
  • Stop calling set_context on Validators. #​8589
  • Return NotImplemented from ErrorDetails.__ne__. #​8538
  • Don't evaluate DateTimeField.default_timezone when a custom timezone is set. #​8531
  • Make relative URLs clickable in Browseable API. #​8464
  • Support ManyRelatedField falling back to the default value when the attribute specified by dot notation doesn't exist. Matches ManyRelatedField.get_attribute to Field.get_attribute. #​7574
  • Make schemas.openapi.get_reference public. #​7515

Note

PR body was truncated to here.


Configuration

📅 Schedule: (in timezone UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate
renovate Bot force-pushed the renovate/pypi-djangorestframework-vulnerability branch from 6f96f47 to bc9019d Compare September 1, 2026 23:54
@renovate renovate Bot changed the title chore(deps): update dependency djangorestframework to v3.15.2 [security] chore(deps): update dependency djangorestframework to v3.17.2 [security] Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants