Skip to content

Commit 353505e

Browse files
committed
Python: Handle content of Django redirects correctly
1 parent 92dc7dc commit 353505e

File tree

2 files changed

+17
-3
lines changed

2 files changed

+17
-3
lines changed

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,10 @@ private module Django {
732732
ClassInstantiation() { node.getFunction() = classRef().asCfgNode() }
733733

734734
override DataFlow::Node getBody() {
735-
result.asCfgNode() in [node.getArg(0), node.getArgByName("redirect_to")]
735+
// note that even though browsers like Chrome usually doesn't fetch the
736+
// content of a redirect, it is possible to observe the body (for example,
737+
// with cURL).
738+
result.asCfgNode() in [node.getArg(1), node.getArgByName("content")]
736739
}
737740

738741
// How to support the `headers` argument here?
@@ -796,7 +799,10 @@ private module Django {
796799
ClassInstantiation() { node.getFunction() = classRef().asCfgNode() }
797800

798801
override DataFlow::Node getBody() {
799-
result.asCfgNode() in [node.getArg(0), node.getArgByName("redirect_to")]
802+
// note that even though browsers like Chrome usually doesn't fetch the
803+
// content of a redirect, it is possible to observe the body (for example,
804+
// with cURL).
805+
result.asCfgNode() in [node.getArg(1), node.getArgByName("content")]
800806
}
801807

802808
// How to support the `headers` argument here?

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,15 @@ 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 responseBody=Attribute()
21+
return HttpResponseRedirect(request.GET.get("next")) # $HttpResponse mimetype=text/html
22+
23+
def information_exposure_through_redirect(request, as_kw=False):
24+
# This is a contrived example, but possible
25+
private = "private"
26+
if as_kw:
27+
return HttpResponseRedirect(request.GET.get("next"), content=private) # $HttpResponse mimetype=text/html responseBody=private
28+
else:
29+
return HttpResponseRedirect(request.GET.get("next"), private) # $HttpResponse mimetype=text/html responseBody=private
2230

2331
# Ensure that simple subclasses are still vuln to XSS
2432
def xss__not_found(request):

0 commit comments

Comments
 (0)