Python: Update more tests annotations. It looks like we need to allow single-quote strings to support the existing Python use-cases, but let's do that in the next commit.

This commit is contained in:
Mathias Vorreiter Pedersen
2020-10-31 17:40:19 +01:00
parent ed9ad8b5e3
commit 0bc4d52d66
6 changed files with 69 additions and 59 deletions

View File

@@ -0,0 +1,10 @@
| response_test.py:16:12:16:86 | ControlFlowNode for HttpResponse() | Unexpected result: responseBody='<img src="0" onerror="alert(1)">' |
| response_test.py:16:89:16:171 | Comment # $HttpResponse mimetype=text/plain responseBody='<img src="0" onerror="alert(1)">' | Missing result:responseBody='<img |
| response_test.py:21:12:21:56 | ControlFlowNode for HttpResponseRedirect() | Unexpected result: mimetype=text/html; charset=utf-8 |
| response_test.py:21:59:21:132 | Comment # $HttpResponse mimetype=text/html; charset=utf-8 responseBody=Attribute() | Missing result:mimetype=text/html; |
| response_test.py:25:12:25:56 | ControlFlowNode for HttpResponseNotFound() | Unexpected result: mimetype=text/html; charset=utf-8 |
| response_test.py:25:59:25:132 | Comment # $HttpResponse mimetype=text/html; charset=utf-8 responseBody=Attribute() | Missing result:mimetype=text/html; |
| response_test.py:32:16:32:29 | ControlFlowNode for HttpResponse() | Unexpected result: mimetype=text/html; charset=utf-8 |
| response_test.py:32:32:32:80 | Comment # $HttpResponse mimetype=text/html; charset=utf-8 | Missing result:mimetype=text/html; |
| response_test.py:33:5:33:43 | ControlFlowNode for Attribute() | Unexpected result: mimetype=text/html; charset=utf-8 |
| response_test.py:33:46:33:119 | Comment # $HttpResponse mimetype=text/html; charset=utf-8 responseBody=Attribute() | Missing result:mimetype=text/html; |

View File

@@ -4,38 +4,38 @@ from django.http.response import HttpResponse, HttpResponseRedirect, JsonRespons
# FP reported in https://github.com/github/codeql-python-team/issues/38
def safe__json_response(request):
# implicitly sets Content-Type to "application/json"
return JsonResponse({"foo": request.GET.get("foo")}) # $HttpResponse $mimetype=application/json $responseBody=Dict
return JsonResponse({"foo": request.GET.get("foo")}) # $HttpResponse mimetype=application/json responseBody=Dict
# Not an XSS sink, since the Content-Type is not "text/html"
def safe__manual_json_response(request):
json_data = '{"json": "{}"}'.format(request.GET.get("foo"))
return HttpResponse(json_data, content_type="application/json") # $HttpResponse $mimetype=application/json $responseBody=json_data
return HttpResponse(json_data, content_type="application/json") # $HttpResponse mimetype=application/json responseBody=json_data
# Not an XSS sink, since the Content-Type is not "text/html"
def safe__manual_content_type(request):
return HttpResponse('<img src="0" onerror="alert(1)">', content_type="text/plain") # $HttpResponse $mimetype=text/plain $responseBody='<img src="0" onerror="alert(1)">'
return HttpResponse('<img src="0" onerror="alert(1)">', content_type="text/plain") # $HttpResponse mimetype=text/plain responseBody='<img src="0" onerror="alert(1)">'
# XSS FP reported in https://github.com/github/codeql/issues/3466
# Note: This should be an open-redirect sink, but not an XSS sink.
def or__redirect(request):
return HttpResponseRedirect(request.GET.get("next")) # $HttpResponse $mimetype=text/html; charset=utf-8 $responseBody=Attribute()
return HttpResponseRedirect(request.GET.get("next")) # $HttpResponse mimetype=text/html; charset=utf-8 responseBody=Attribute()
# Ensure that simple subclasses are still vuln to XSS
def xss__not_found(request):
return HttpResponseNotFound(request.GET.get("name")) # $HttpResponse $mimetype=text/html; charset=utf-8 $responseBody=Attribute()
return HttpResponseNotFound(request.GET.get("name")) # $HttpResponse mimetype=text/html; charset=utf-8 responseBody=Attribute()
# Ensure we still have an XSS sink when manually setting the content_type to HTML
def xss__manual_response_type(request):
return HttpResponse(request.GET.get("name"), content_type="text/html; charset=utf-8") # $HttpResponse $mimetype=text/html $responseBody=Attribute()
return HttpResponse(request.GET.get("name"), content_type="text/html; charset=utf-8") # $HttpResponse mimetype=text/html responseBody=Attribute()
def xss__write(request):
response = HttpResponse() # $HttpResponse $mimetype=text/html; charset=utf-8
response.write(request.GET.get("name")) # $HttpResponse $mimetype=text/html; charset=utf-8 $responseBody=Attribute()
response = HttpResponse() # $HttpResponse mimetype=text/html; charset=utf-8
response.write(request.GET.get("name")) # $HttpResponse mimetype=text/html; charset=utf-8 responseBody=Attribute()
# This is safe but probably a bug if the argument to `write` is not a result of `json.dumps` or similar.
def safe__write_json(request):
response = JsonResponse() # $HttpResponse $mimetype=application/json
response.write(request.GET.get("name")) # $HttpResponse $mimetype=application/json $responseBody=Attribute()
response = JsonResponse() # $HttpResponse mimetype=application/json
response.write(request.GET.get("name")) # $HttpResponse mimetype=application/json responseBody=Attribute()
# Ensure manual subclasses are vulnerable
class CustomResponse(HttpResponse):
@@ -43,11 +43,11 @@ class CustomResponse(HttpResponse):
super().__init__(content, *args, content_type="text/html", **kwargs)
def xss__custom_response(request):
return CustomResponse("ACME Responses", request.GET("name")) # $HttpResponse $f-:mimetype=text/html $f-:responseBody=Attribute() $f+:responseBody="ACME Responses"
return CustomResponse("ACME Responses", request.GET("name")) # $HttpResponse MISSING: mimetype=text/html responseBody=Attribute() SPURIOUS: responseBody="ACME Responses"
class CustomJsonResponse(JsonResponse):
def __init__(self, banner, content, *args, **kwargs):
super().__init__(content, *args, content_type="text/html", **kwargs)
def safe__custom_json_response(request):
return CustomJsonResponse("ACME Responses", {"foo": request.GET.get("foo")}) # $HttpResponse $mimetype=application/json $f-:responseBody=Dict $f+:responseBody="ACME Responses"
return CustomJsonResponse("ACME Responses", {"foo": request.GET.get("foo")}) # $HttpResponse mimetype=application/json MISSING: responseBody=Dict SPURIOUS: responseBody="ACME Responses"

View File

@@ -33,7 +33,7 @@ def dangerous2(): # $routeHandler
x = request.form['param0']
if request.method == "POST":
return request.form['param1'] # $HttpResponse
return None # $f+:HttpResponse
return None # $ SPURIOUS: HttpResponse
@app.route("/unsafe") # $routeSetup="/unsafe"
def unsafe(): # $routeHandler

View File

@@ -7,7 +7,7 @@ app = Flask(__name__)
@app.route("/html1") # $routeSetup="/html1"
def html1(): # $routeHandler
return "<h1>hello</h1>" # $HttpResponse $mimetype=text/html $responseBody="<h1>hello</h1>"
return "<h1>hello</h1>" # $HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
@app.route("/html2") # $routeSetup="/html2"
@@ -15,14 +15,14 @@ def html2(): # $routeHandler
# note that response saved in a variable intentionally -- we wan the annotations to
# show that we recognize the response creation, and not the return (hopefully). (and
# do the same in the following of the file)
resp = make_response("<h1>hello</h1>") # $HttpResponse $mimetype=text/html $responseBody="<h1>hello</h1>"
return resp # $f+:HttpResponse $f+:mimetype=text/html $f+:responseBody=resp
resp = make_response("<h1>hello</h1>") # $HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/html3") # $routeSetup="/html3"
def html3(): # $routeHandler
resp = app.make_response("<h1>hello</h1>") # $HttpResponse $mimetype=text/html $responseBody="<h1>hello</h1>"
return resp # $f+:HttpResponse $f+:mimetype=text/html $f+:responseBody=resp
resp = app.make_response("<h1>hello</h1>") # $HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
# TODO: Create test-cases for the many ways that `make_response` can be used
@@ -31,38 +31,38 @@ def html3(): # $routeHandler
@app.route("/html4") # $routeSetup="/html4"
def html4(): # $routeHandler
resp = Response("<h1>hello</h1>") # $HttpResponse $mimetype=text/html $responseBody="<h1>hello</h1>"
return resp # $f+:HttpResponse $f+:mimetype=text/html $f+:responseBody=resp
resp = Response("<h1>hello</h1>") # $HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/html5") # $routeSetup="/html5"
def html5(): # $routeHandler
# note: flask.Flask.response_class is set to `flask.Response` by default.
# it can be overridden, but we don't try to handle that right now.
resp = Flask.response_class("<h1>hello</h1>") # $HttpResponse $mimetype=text/html $responseBody="<h1>hello</h1>"
return resp # $f+:HttpResponse $f+:mimetype=text/html $f+:responseBody=resp
resp = Flask.response_class("<h1>hello</h1>") # $HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/html6") # $routeSetup="/html6"
def html6(): # $routeHandler
# note: app.response_class (flask.Flask.response_class) is set to `flask.Response` by default.
# it can be overridden, but we don't try to handle that right now.
resp = app.response_class("<h1>hello</h1>") # $HttpResponse $mimetype=text/html $responseBody="<h1>hello</h1>"
return resp # $f+:HttpResponse $f+:mimetype=text/html $f+:responseBody=resp
resp = app.response_class("<h1>hello</h1>") # $HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/html7") # $routeSetup="/html7"
def html7(): # $routeHandler
resp = make_response() # $HttpResponse $mimetype=text/html
resp.set_data("<h1>hello</h1>") # $f-:responseBody="<h1>hello</h1>"
return resp # $f+:HttpResponse $f+:mimetype=text/html $f+:responseBody=resp
resp = make_response() # $HttpResponse mimetype=text/html
resp.set_data("<h1>hello</h1>") # $ MISSING: responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/jsonify") # $routeSetup="/jsonify"
def jsonify_route(): # $routeHandler
data = {"foo": "bar"}
resp = jsonify(data) # $f-:HttpResponse $f-:mimetype=application/json $f-:responseBody=data
return resp # $f+:HttpResponse $f+:mimetype=text/html $f+:responseBody=resp
resp = jsonify(data) # $ MISSING: HttpResponse mimetype=application/json responseBody=data
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
################################################################################
# Tricky return handling
@@ -73,19 +73,19 @@ def tricky_return1(): # $routeHandler
if "raw" in request.args:
resp = "<h1>hellu</h1>"
else:
resp = make_response("<h1>hello</h1>") # $HttpResponse $mimetype=text/html $responseBody="<h1>hello</h1>"
return resp # $HttpResponse $mimetype=text/html $responseBody=resp
resp = make_response("<h1>hello</h1>") # $HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
return resp # $HttpResponse mimetype=text/html responseBody=resp
def helper():
if "raw" in request.args:
return "<h1>hellu</h1>"
else:
return make_response("<h1>hello</h1>") # $HttpResponse $mimetype=text/html $responseBody="<h1>hello</h1>"
return make_response("<h1>hello</h1>") # $HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
@app.route("/tricky-return2") # $routeSetup="/tricky-return2"
def tricky_return2(): # $routeHandler
resp = helper()
return resp # $HttpResponse $mimetype=text/html $responseBody=resp
return resp # $HttpResponse mimetype=text/html responseBody=resp
################################################################################
@@ -95,16 +95,16 @@ def tricky_return2(): # $routeHandler
@app.route("/content-type/response-modification1") # $routeSetup="/content-type/response-modification1"
def response_modification1(): # $routeHandler
resp = make_response("<h1>hello</h1>") # $HttpResponse $mimetype=text/html $responseBody="<h1>hello</h1>"
resp.content_type = "text/plain" # $f-:HttpResponse $f-:mimetype=text/plain
return resp # $f+:HttpResponse $f+:mimetype=text/html $f+:responseBody=resp
resp = make_response("<h1>hello</h1>") # $HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
resp.content_type = "text/plain" # $ MISSING: HttpResponse mimetype=text/plain
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/content-type/response-modification2") # $routeSetup="/content-type/response-modification2"
def response_modification2(): # $routeHandler
resp = make_response("<h1>hello</h1>") # $HttpResponse $mimetype=text/html $responseBody="<h1>hello</h1>"
resp.headers["content-type"] = "text/plain" # $f-:HttpResponse $f-:mimetype=text/plain
return resp # $f+:HttpResponse $f+:mimetype=text/html $f+:responseBody=resp
resp = make_response("<h1>hello</h1>") # $HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
resp.headers["content-type"] = "text/plain" # $ MISSING: HttpResponse mimetype=text/plain
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
# Exploration of mimetype/content_type/headers arguments to `app.response_class` -- things can get tricky
@@ -113,60 +113,60 @@ def response_modification2(): # $routeHandler
@app.route("/content-type/Response1") # $routeSetup="/content-type/Response1"
def Response1(): # $routeHandler
resp = Response("<h1>hello</h1>", mimetype="text/plain") # $HttpResponse $mimetype=text/plain $responseBody="<h1>hello</h1>"
return resp # $f+:HttpResponse $f+:mimetype=text/html $f+:responseBody=resp
resp = Response("<h1>hello</h1>", mimetype="text/plain") # $HttpResponse mimetype=text/plain responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/content-type/Response2") # $routeSetup="/content-type/Response2"
def Response2(): # $routeHandler
resp = Response("<h1>hello</h1>", content_type="text/plain; charset=utf-8") # $HttpResponse $mimetype=text/plain $responseBody="<h1>hello</h1>"
return resp # $f+:HttpResponse $f+:mimetype=text/html $f+:responseBody=resp
resp = Response("<h1>hello</h1>", content_type="text/plain; charset=utf-8") # $HttpResponse mimetype=text/plain responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/content-type/Response3") # $routeSetup="/content-type/Response3"
def Response3(): # $routeHandler
# content_type argument takes priority (and result is text/plain)
resp = Response("<h1>hello</h1>", content_type="text/plain; charset=utf-8", mimetype="text/html") # $HttpResponse $mimetype=text/plain $responseBody="<h1>hello</h1>"
return resp # $f+:HttpResponse $f+:mimetype=text/html $f+:responseBody=resp
resp = Response("<h1>hello</h1>", content_type="text/plain; charset=utf-8", mimetype="text/html") # $HttpResponse mimetype=text/plain responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/content-type/Response4") # $routeSetup="/content-type/Response4"
def Response4(): # $routeHandler
# note: capitalization of Content-Type does not matter
resp = Response("<h1>hello</h1>", headers={"Content-TYPE": "text/plain"}) # $HttpResponse $f+:mimetype=text/html $f-:mimetype=text/plain $responseBody="<h1>hello</h1>"
return resp # $f+:HttpResponse $f+:mimetype=text/html $f+:responseBody=resp
resp = Response("<h1>hello</h1>", headers={"Content-TYPE": "text/plain"}) # $HttpResponse responseBody="<h1>hello</h1>" SPURIOUS: mimetype=text/html MISSING: mimetype=text/plain
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/content-type/Response5") # $routeSetup="/content-type/Response5"
def Response5(): # $routeHandler
# content_type argument takes priority (and result is text/plain)
# note: capitalization of Content-Type does not matter
resp = Response("<h1>hello</h1>", headers={"Content-TYPE": "text/html"}, content_type="text/plain; charset=utf-8") # $HttpResponse $mimetype=text/plain $responseBody="<h1>hello</h1>"
return resp # $f+:HttpResponse $f+:mimetype=text/html $f+:responseBody=resp
resp = Response("<h1>hello</h1>", headers={"Content-TYPE": "text/html"}, content_type="text/plain; charset=utf-8") # $HttpResponse mimetype=text/plain responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/content-type/Response6") # $routeSetup="/content-type/Response6"
def Response6(): # $routeHandler
# mimetype argument takes priority over header (and result is text/plain)
# note: capitalization of Content-Type does not matter
resp = Response("<h1>hello</h1>", headers={"Content-TYPE": "text/html"}, mimetype="text/plain") # $HttpResponse $mimetype=text/plain $responseBody="<h1>hello</h1>"
return resp # $f+:HttpResponse $f+:mimetype=text/html $f+:responseBody=resp
resp = Response("<h1>hello</h1>", headers={"Content-TYPE": "text/html"}, mimetype="text/plain") # $HttpResponse mimetype=text/plain responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/content-type/Flask-response-class") # $routeSetup="/content-type/Flask-response-class"
def Flask_response_class(): # $routeHandler
# note: flask.Flask.response_class is set to `flask.Response` by default.
# it can be overridden, but we don't try to handle that right now.
resp = Flask.response_class("<h1>hello</h1>", mimetype="text/plain") # $HttpResponse $mimetype=text/plain $responseBody="<h1>hello</h1>"
return resp # $f+:HttpResponse $f+:mimetype=text/html $f+:responseBody=resp
resp = Flask.response_class("<h1>hello</h1>", mimetype="text/plain") # $HttpResponse mimetype=text/plain responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/content-type/app-response-class") # $routeSetup="/content-type/app-response-class"
def app_response_class(): # $routeHandler
# note: app.response_class (flask.Flask.response_class) is set to `flask.Response` by default.
# it can be overridden, but we don't try to handle that right now.
resp = app.response_class("<h1>hello</h1>", mimetype="text/plain") # $HttpResponse $mimetype=text/plain $responseBody="<h1>hello</h1>"
return resp # $f+:HttpResponse $f+:mimetype=text/html $f+:responseBody=resp
resp = app.response_class("<h1>hello</h1>", mimetype="text/plain") # $HttpResponse mimetype=text/plain responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
# TODO: add tests for setting status code

View File

@@ -3,5 +3,5 @@ open(file="filepath") # $getAPathArgument="filepath"
o = open
o("filepath") # f-:$getAPathArgument="filepath"
o(file="filepath") # f-:$getAPathArgument="filepath"
o("filepath") # $ MISSING: getAPathArgument="filepath"
o(file="filepath") # $ MISSING: getAPathArgument="filepath"

View File

@@ -1,8 +1,8 @@
s = "taintedString"
if s.startswith("tainted"): # $checks=s $branch=true
if s.startswith("tainted"): # $checks=s branch=true
pass
sw = s.startswith # $f-:checks=s $f-:branch=true
sw = s.startswith # $ MISSING: checks=s branch=true
if sw("safe"):
pass