Skip to content

Commit 92dc7dc

Browse files
committed
Python: Use mimetype instead of content-type in django modeling
This enables the XSS query to actually find results from django responses.
1 parent 22b4df0 commit 92dc7dc

File tree

2 files changed

+16
-16
lines changed

2 files changed

+16
-16
lines changed

python/ql/src/semmle/python/frameworks/Django.qll

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,7 @@ private module Django {
670670
result.asCfgNode() in [node.getArg(1), node.getArgByName("content_type")]
671671
}
672672

673-
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
673+
override string getMimetypeDefault() { result = "text/html" }
674674
}
675675

676676
/** Gets a reference to an instance of `django.http.response.HttpResponse`. */
@@ -738,7 +738,7 @@ private module Django {
738738
// How to support the `headers` argument here?
739739
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
740740

741-
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
741+
override string getMimetypeDefault() { result = "text/html" }
742742
}
743743

744744
/** Gets a reference to an instance of `django.http.response.HttpResponseRedirect`. */
@@ -802,7 +802,7 @@ private module Django {
802802
// How to support the `headers` argument here?
803803
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
804804

805-
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
805+
override string getMimetypeDefault() { result = "text/html" }
806806
}
807807

808808
/** Gets a reference to an instance of `django.http.response.HttpResponsePermanentRedirect`. */
@@ -928,7 +928,7 @@ private module Django {
928928
// How to support the `headers` argument here?
929929
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
930930

931-
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
931+
override string getMimetypeDefault() { result = "text/html" }
932932
}
933933

934934
/** Gets a reference to an instance of `django.http.response.HttpResponseBadRequest`. */
@@ -992,7 +992,7 @@ private module Django {
992992
// How to support the `headers` argument here?
993993
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
994994

995-
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
995+
override string getMimetypeDefault() { result = "text/html" }
996996
}
997997

998998
/** Gets a reference to an instance of `django.http.response.HttpResponseNotFound`. */
@@ -1056,7 +1056,7 @@ private module Django {
10561056
// How to support the `headers` argument here?
10571057
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
10581058

1059-
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
1059+
override string getMimetypeDefault() { result = "text/html" }
10601060
}
10611061

10621062
/** Gets a reference to an instance of `django.http.response.HttpResponseForbidden`. */
@@ -1121,7 +1121,7 @@ private module Django {
11211121
// How to support the `headers` argument here?
11221122
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
11231123

1124-
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
1124+
override string getMimetypeDefault() { result = "text/html" }
11251125
}
11261126

11271127
/** Gets a reference to an instance of `django.http.response.HttpResponseNotAllowed`. */
@@ -1185,7 +1185,7 @@ private module Django {
11851185
// How to support the `headers` argument here?
11861186
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
11871187

1188-
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
1188+
override string getMimetypeDefault() { result = "text/html" }
11891189
}
11901190

11911191
/** Gets a reference to an instance of `django.http.response.HttpResponseGone`. */
@@ -1249,7 +1249,7 @@ private module Django {
12491249
// How to support the `headers` argument here?
12501250
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
12511251

1252-
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
1252+
override string getMimetypeDefault() { result = "text/html" }
12531253
}
12541254

12551255
/** Gets a reference to an instance of `django.http.response.HttpResponseServerError`. */
@@ -1380,7 +1380,7 @@ private module Django {
13801380
// How to support the `headers` argument here?
13811381
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
13821382

1383-
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
1383+
override string getMimetypeDefault() { result = "text/html" }
13841384
}
13851385

13861386
/** Gets a reference to an instance of `django.http.response.StreamingHttpResponse`. */
@@ -1444,7 +1444,7 @@ private module Django {
14441444
// How to support the `headers` argument here?
14451445
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
14461446

1447-
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
1447+
override string getMimetypeDefault() { result = "text/html" }
14481448
}
14491449

14501450
/** Gets a reference to an instance of `django.http.response.FileResponse`. */

python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,19 @@ def safe__manual_content_type(request):
1818
# XSS FP reported in https://github.com/github/codeql/issues/3466
1919
# Note: This should be an open-redirect sink, but not an XSS sink.
2020
def or__redirect(request):
21-
return HttpResponseRedirect(request.GET.get("next")) # $HttpResponse mimetype="text/html; charset=utf-8" responseBody=Attribute()
21+
return HttpResponseRedirect(request.GET.get("next")) # $HttpResponse mimetype=text/html responseBody=Attribute()
2222

2323
# Ensure that simple subclasses are still vuln to XSS
2424
def xss__not_found(request):
25-
return HttpResponseNotFound(request.GET.get("name")) # $HttpResponse mimetype="text/html; charset=utf-8" responseBody=Attribute()
25+
return HttpResponseNotFound(request.GET.get("name")) # $HttpResponse mimetype=text/html responseBody=Attribute()
2626

2727
# Ensure we still have an XSS sink when manually setting the content_type to HTML
2828
def xss__manual_response_type(request):
2929
return HttpResponse(request.GET.get("name"), content_type="text/html; charset=utf-8") # $HttpResponse mimetype=text/html responseBody=Attribute()
3030

3131
def xss__write(request):
32-
response = HttpResponse() # $HttpResponse mimetype="text/html; charset=utf-8"
33-
response.write(request.GET.get("name")) # $HttpResponse mimetype="text/html; charset=utf-8" responseBody=Attribute()
32+
response = HttpResponse() # $HttpResponse mimetype=text/html
33+
response.write(request.GET.get("name")) # $HttpResponse mimetype=text/html responseBody=Attribute()
3434

3535
# This is safe but probably a bug if the argument to `write` is not a result of `json.dumps` or similar.
3636
def safe__write_json(request):
@@ -50,4 +50,4 @@ def __init__(self, banner, content, *args, **kwargs):
5050
super().__init__(content, *args, content_type="text/html", **kwargs)
5151

5252
def safe__custom_json_response(request):
53-
return CustomJsonResponse("ACME Responses", {"foo": request.GET.get("foo")}) # $HttpResponse mimetype=application/json MISSING: responseBody=Dict SPURIOUS: responseBody="ACME Responses"
53+
return CustomJsonResponse("ACME Responses", {"foo": request.GET.get("foo")}) # $HttpResponse mimetype=application/json MISSING: responseBody=Dict SPURIOUS: responseBody="ACME Responses"

0 commit comments

Comments
 (0)