@@ -43,6 +43,131 @@ the industry-standard 90 days. Confirmed vulnerabilities with a
43
43
44
44
.. _our public Trac instance: https://code.djangoproject.com/query
45
45
46
+ Reporting guidelines
47
+ --------------------
48
+
49
+ Include a runnable proof of concept
50
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
51
+
52
+ Please privately share a minimal Django project or code snippet that
53
+ demonstrates the potential vulnerability. Include clear instructions on how to
54
+ set up, run, and reproduce the issue.
55
+
56
+ Please do not attach screenshots of code.
57
+
58
+ User input must be sanitized
59
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
60
+
61
+ Reports based on a failure to sanitize user input are not valid security
62
+ vulnerabilities. It is the developer's responsibility to properly handle user
63
+ input. This principle is explained in our :ref:`security documentation
64
+ <sanitize-user-input>`.
65
+
66
+ For example, the following is **not considered valid** because ``email`` has
67
+ not been sanitized::
68
+
69
+ from django.core.mail import send_mail
70
+ from django.http import JsonResponse
71
+
72
+
73
+ def my_proof_of_concept(request):
74
+ email = request.GET.get("email", "")
75
+ send_mail("Email subject", "Email body", email, ["
[email protected] "])
76
+ return JsonResponse(status=200)
77
+
78
+ Developers must **always validate and sanitize input** before using it. The
79
+ correct approach would be to use a Django form to ensure ``email`` is properly
80
+ validated::
81
+
82
+ from django import forms
83
+ from django.core.mail import send_mail
84
+ from django.http import JsonResponse
85
+
86
+
87
+ class EmailForm(forms.Form):
88
+ email = forms.EmailField()
89
+
90
+
91
+ def my_proof_of_concept(request):
92
+ form = EmailForm(request.GET)
93
+ if form.is_valid():
94
+ send_mail(
95
+ "Email subject",
96
+ "Email body",
97
+ form.cleaned_data["email"],
98
+
99
+ )
100
+ return JsonResponse(status=200)
101
+ return JsonResponse(form.errors, status=400)
102
+
103
+ Similarly, as Django's raw SQL constructs (such as :meth:`~.QuerySet.extra` and
104
+ :class:`.RawSQL` expression) provide developers with full control over the
105
+ query, they are insecure if user input is not properly handled. As explained in
106
+ our :ref:`security documentation <sql-injection-protection>`, it is the
107
+ developer's responsibility to safely process user input for these functions.
108
+
109
+ For instance, the following is **not considered valid** because ``query`` has
110
+ not been sanitized::
111
+
112
+ from django.shortcuts import HttpResponse
113
+ from .models import MyModel
114
+
115
+
116
+ def my_proof_of_concept(request):
117
+ query = request.GET.get("query", "")
118
+ q = MyModel.objects.extra(select={"id": query})
119
+ return HttpResponse(q.values())
120
+
121
+ Request headers and URLs must be under 8K bytes
122
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
123
+
124
+ To prevent denial-of-service (DoS) attacks, production-grade servers impose
125
+ limits on request header and URL sizes. For example, by default Gunicorn allows
126
+ up to roughly:
127
+
128
+ * `4k bytes for a URL`_
129
+ * `8K bytes for a request header`_
130
+
131
+ Other web servers, such as Nginx and Apache, have similar restrictions to
132
+ prevent excessive resource consumption.
133
+
134
+ Consequently, the Django security team will not consider reports that rely on
135
+ request headers or URLs exceeding 8K bytes, as such inputs are already
136
+ mitigated at the server level in production environments.
137
+
138
+ .. admonition:: :djadmin:`runserver` should never be used in production
139
+
140
+ Django's built-in development server does not enforce these limits because
141
+ it is not designed to be a production server.
142
+
143
+ .. _`4k bytes for a URL`: https://docs.gunicorn.org/en/stable/settings.html#limit-request-line
144
+ .. _`8k bytes for a request header`: https://docs.gunicorn.org/en/stable/settings.html#limit-request-field-size
145
+
146
+ The request body must be under 2.5 MB
147
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
148
+
149
+ The :setting:`DATA_UPLOAD_MAX_MEMORY_SIZE` setting limits the default maximum
150
+ request body size to 2.5 MB.
151
+
152
+ As this is enforced on all production-grade Django projects by default, a proof
153
+ of concept must not exceed 2.5 MB in the request body to be considered valid.
154
+
155
+ Issues resulting from large, but potentially reasonable setting values, should
156
+ be reported using the `public ticket tracker`_ for hardening.
157
+
158
+ .. _public ticket tracker: https://code.djangoproject.com/
159
+
160
+ Code under test must feasibly exist in a Django project
161
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
162
+
163
+ The proof of concept must plausibly occur in a production-grade Django
164
+ application, reflecting real-world scenarios and following standard development
165
+ practices.
166
+
167
+ Django contains many private and undocumented functions that are not part of
168
+ its public API. If a vulnerability depends on directly calling these internal
169
+ functions in an unsafe way, it will not be considered a valid security issue.
170
+
46
171
.. _security-report-evaluation:
47
172
48
173
How does Django evaluate a report
0 commit comments