Add test cases

This commit is contained in:
Joe Farebrother
2024-04-03 10:32:27 +01:00
parent 68d90918cf
commit b9984beb16
5 changed files with 42 additions and 16 deletions

View File

@@ -222,10 +222,13 @@ module Flask {
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
/** An `Headers` instance that is part of a Flask response. */
private class FlaskResponseHeadersInstances extends Werkzeug::Headers::InstanceSource {
FlaskResponseHeadersInstances() { this = request().getMember("headers").asSource() }
private class FlaskResponseHeadersInstances extends Werkzeug::Headers::InstanceSource
{
FlaskResponseHeadersInstances() {
this.(DataFlow::AttrRead).getObject() = instance() and
this.(DataFlow::AttrRead).getAttributeName() = "headers"
}
}
// TODO: headers arg to make_response
}

View File

@@ -188,8 +188,7 @@ module Werkzeug {
DataFlow::MethodCallNode
{
HeaderWriteCall() {
this.getObject() = instance() and
this.getMethodName() = ["add", "add_header", "set", "set_default", "__setitem__"]
this.calls(instance(), ["add", "add_header", "set", "set_default", "__setitem__"])
}
override DataFlow::Node getNameArg() { result = this.getArg(0) }

View File

@@ -0,0 +1,21 @@
edges
| flask_tests.py:1:29:1:35 | ControlFlowNode for ImportMember | flask_tests.py:1:29:1:35 | ControlFlowNode for request | provenance | |
| flask_tests.py:1:29:1:35 | ControlFlowNode for request | flask_tests.py:20:18:20:24 | ControlFlowNode for request | provenance | |
| flask_tests.py:1:29:1:35 | ControlFlowNode for request | flask_tests.py:29:18:29:24 | ControlFlowNode for request | provenance | |
| flask_tests.py:20:5:20:14 | ControlFlowNode for rfs_header | flask_tests.py:23:22:23:31 | ControlFlowNode for rfs_header | provenance | |
| flask_tests.py:20:18:20:24 | ControlFlowNode for request | flask_tests.py:20:5:20:14 | ControlFlowNode for rfs_header | provenance | |
| flask_tests.py:29:5:29:14 | ControlFlowNode for rfs_header | flask_tests.py:32:22:32:31 | ControlFlowNode for rfs_header | provenance | |
| flask_tests.py:29:18:29:24 | ControlFlowNode for request | flask_tests.py:29:5:29:14 | ControlFlowNode for rfs_header | provenance | |
nodes
| flask_tests.py:1:29:1:35 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember |
| flask_tests.py:1:29:1:35 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| flask_tests.py:20:5:20:14 | ControlFlowNode for rfs_header | semmle.label | ControlFlowNode for rfs_header |
| flask_tests.py:20:18:20:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| flask_tests.py:23:22:23:31 | ControlFlowNode for rfs_header | semmle.label | ControlFlowNode for rfs_header |
| flask_tests.py:29:5:29:14 | ControlFlowNode for rfs_header | semmle.label | ControlFlowNode for rfs_header |
| flask_tests.py:29:18:29:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| flask_tests.py:32:22:32:31 | ControlFlowNode for rfs_header | semmle.label | ControlFlowNode for rfs_header |
subpaths
#select
| flask_tests.py:23:22:23:31 | ControlFlowNode for rfs_header | flask_tests.py:1:29:1:35 | ControlFlowNode for ImportMember | flask_tests.py:23:22:23:31 | ControlFlowNode for rfs_header | This HTTP header is constructed from a $@. | flask_tests.py:1:29:1:35 | ControlFlowNode for ImportMember | user-provided value |
| flask_tests.py:32:22:32:31 | ControlFlowNode for rfs_header | flask_tests.py:1:29:1:35 | ControlFlowNode for ImportMember | flask_tests.py:32:22:32:31 | ControlFlowNode for rfs_header | This HTTP header is constructed from a $@. | flask_tests.py:1:29:1:35 | ControlFlowNode for ImportMember | user-provided value |

View File

@@ -0,0 +1 @@
Security/CWE-113/HeaderInjection.ql

View File

@@ -9,8 +9,9 @@ def werkzeug_headers():
rfs_header = request.args["rfs_header"]
response = Response()
headers = Headers()
headers.add("HeaderName", rfs_header)
response.headers = headers
headers.add("HeaderName", rfs_header) # GOOD: Newlines are rejected from header value.
headers.add(rfs_header, "HeaderValue") # BAD: User controls header name. Not yet found.
response.headers = headers
return response
@@ -18,16 +19,18 @@ def werkzeug_headers():
def flask_Response():
rfs_header = request.args["rfs_header"]
response = Response()
response.headers['HeaderName'] = rfs_header
response.headers['HeaderName'] = rfs_header # GOOD
response.headers[rfs_header] = "HeaderValue" # BAD
return response
@app.route("/flask_make_response")
def flask_make_response():
rfs_header = request.args["rfs_header"]
resp = make_response("hello")
resp.headers['HeaderName'] = rfs_header
return resp
response = make_response("hello")
response.headers['HeaderName'] = rfs_header # GOOD
response.headers[rfs_header] = "HeaderValue" # BAD
return response
@app.route("/flask_make_response_extend")
@@ -35,13 +38,12 @@ def flask_make_response_extend():
rfs_header = request.args["rfs_header"]
resp = make_response("hello")
resp.headers.extend(
{'HeaderName': rfs_header})
{'HeaderName': rfs_header}) # GOOD
resp.headers.extend(
{rfs_header: "HeaderValue"}) # BAD but not yet found
return resp
@app.route("/Response_arg")
def Response_arg():
return Response(headers={'HeaderName': request.args["rfs_header"]})
# if __name__ == "__main__":
# app.run(debug=True)
return Response(headers={'HeaderName': request.args["rfs_header"], request.args["rfs_header"]: "HeaderValue"}) # BAD but not yet found