mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
Merge pull request #10535 from RasmusWL/flask-jsonify
Python: Model `flask.jsonify`
This commit is contained in:
4
python/ql/lib/change-notes/2022-09-22-flask-jsonify.md
Normal file
4
python/ql/lib/change-notes/2022-09-22-flask-jsonify.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* Added modeling of creating Flask responses with `flask.jsonify`.
|
||||||
@@ -171,6 +171,22 @@ module Flask {
|
|||||||
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
|
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A call to `flask.jsonify` function. This creates a JSON response.
|
||||||
|
*
|
||||||
|
* See
|
||||||
|
* - https://flask.palletsprojects.com/en/2.2.x/api/#flask.json.jsonify
|
||||||
|
*/
|
||||||
|
private class FlaskJsonifyCall extends InstanceSource, DataFlow::CallCfgNode {
|
||||||
|
FlaskJsonifyCall() { this = API::moduleImport("flask").getMember("jsonify").getACall() }
|
||||||
|
|
||||||
|
override DataFlow::Node getBody() { result in [this.getArg(_), this.getArgByName(_)] }
|
||||||
|
|
||||||
|
override string getMimetypeDefault() { result = "application/json" }
|
||||||
|
|
||||||
|
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
|
||||||
|
}
|
||||||
|
|
||||||
/** Gets a reference to an instance of `flask.Response`. */
|
/** Gets a reference to an instance of `flask.Response`. */
|
||||||
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) {
|
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) {
|
||||||
t.start() and
|
t.start() and
|
||||||
|
|||||||
@@ -66,8 +66,8 @@ def html8(): # $requestHandler
|
|||||||
|
|
||||||
@app.route("/jsonify") # $routeSetup="/jsonify"
|
@app.route("/jsonify") # $routeSetup="/jsonify"
|
||||||
def jsonify_route(): # $requestHandler
|
def jsonify_route(): # $requestHandler
|
||||||
data = {"foo": "bar"}
|
x = "x"; y = "y"; z = "z"
|
||||||
resp = jsonify(data) # $ MISSING: HttpResponse mimetype=application/json responseBody=data
|
resp = jsonify(x, y, z=z) # $ HttpResponse mimetype=application/json responseBody=x responseBody=y responseBody=z
|
||||||
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
|
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ edges
|
|||||||
| test.py:50:29:50:31 | ControlFlowNode for err | test.py:50:16:50:32 | ControlFlowNode for format_error() |
|
| test.py:50:29:50:31 | ControlFlowNode for err | test.py:50:16:50:32 | ControlFlowNode for format_error() |
|
||||||
| test.py:50:29:50:31 | ControlFlowNode for err | test.py:52:18:52:20 | ControlFlowNode for msg |
|
| test.py:50:29:50:31 | ControlFlowNode for err | test.py:52:18:52:20 | ControlFlowNode for msg |
|
||||||
| test.py:52:18:52:20 | ControlFlowNode for msg | test.py:53:12:53:27 | ControlFlowNode for BinaryExpr |
|
| test.py:52:18:52:20 | ControlFlowNode for msg | test.py:53:12:53:27 | ControlFlowNode for BinaryExpr |
|
||||||
|
| test.py:65:25:65:25 | SSA variable e | test.py:66:24:66:40 | ControlFlowNode for Dict |
|
||||||
nodes
|
nodes
|
||||||
| test.py:16:16:16:37 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
| test.py:16:16:16:37 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||||
| test.py:23:25:23:25 | SSA variable e | semmle.label | SSA variable e |
|
| test.py:23:25:23:25 | SSA variable e | semmle.label | SSA variable e |
|
||||||
@@ -16,6 +17,8 @@ nodes
|
|||||||
| test.py:50:29:50:31 | ControlFlowNode for err | semmle.label | ControlFlowNode for err |
|
| test.py:50:29:50:31 | ControlFlowNode for err | semmle.label | ControlFlowNode for err |
|
||||||
| test.py:52:18:52:20 | ControlFlowNode for msg | semmle.label | ControlFlowNode for msg |
|
| test.py:52:18:52:20 | ControlFlowNode for msg | semmle.label | ControlFlowNode for msg |
|
||||||
| test.py:53:12:53:27 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
|
| test.py:53:12:53:27 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
|
||||||
|
| test.py:65:25:65:25 | SSA variable e | semmle.label | SSA variable e |
|
||||||
|
| test.py:66:24:66:40 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
|
||||||
subpaths
|
subpaths
|
||||||
| test.py:50:29:50:31 | ControlFlowNode for err | test.py:52:18:52:20 | ControlFlowNode for msg | test.py:53:12:53:27 | ControlFlowNode for BinaryExpr | test.py:50:16:50:32 | ControlFlowNode for format_error() |
|
| test.py:50:29:50:31 | ControlFlowNode for err | test.py:52:18:52:20 | ControlFlowNode for msg | test.py:53:12:53:27 | ControlFlowNode for BinaryExpr | test.py:50:16:50:32 | ControlFlowNode for format_error() |
|
||||||
#select
|
#select
|
||||||
@@ -23,3 +26,4 @@ subpaths
|
|||||||
| test.py:24:16:24:16 | ControlFlowNode for e | test.py:23:25:23:25 | SSA variable e | test.py:24:16:24:16 | ControlFlowNode for e | $@ flows to this location and may be exposed to an external user. | test.py:23:25:23:25 | SSA variable e | Stack trace information |
|
| test.py:24:16:24:16 | ControlFlowNode for e | test.py:23:25:23:25 | SSA variable e | test.py:24:16:24:16 | ControlFlowNode for e | $@ flows to this location and may be exposed to an external user. | test.py:23:25:23:25 | SSA variable e | Stack trace information |
|
||||||
| test.py:32:16:32:30 | ControlFlowNode for Attribute | test.py:31:25:31:25 | SSA variable e | test.py:32:16:32:30 | ControlFlowNode for Attribute | $@ flows to this location and may be exposed to an external user. | test.py:31:25:31:25 | SSA variable e | Stack trace information |
|
| test.py:32:16:32:30 | ControlFlowNode for Attribute | test.py:31:25:31:25 | SSA variable e | test.py:32:16:32:30 | ControlFlowNode for Attribute | $@ flows to this location and may be exposed to an external user. | test.py:31:25:31:25 | SSA variable e | Stack trace information |
|
||||||
| test.py:50:16:50:32 | ControlFlowNode for format_error() | test.py:49:15:49:36 | ControlFlowNode for Attribute() | test.py:50:16:50:32 | ControlFlowNode for format_error() | $@ flows to this location and may be exposed to an external user. | test.py:49:15:49:36 | ControlFlowNode for Attribute() | Stack trace information |
|
| test.py:50:16:50:32 | ControlFlowNode for format_error() | test.py:49:15:49:36 | ControlFlowNode for Attribute() | test.py:50:16:50:32 | ControlFlowNode for format_error() | $@ flows to this location and may be exposed to an external user. | test.py:49:15:49:36 | ControlFlowNode for Attribute() | Stack trace information |
|
||||||
|
| test.py:66:24:66:40 | ControlFlowNode for Dict | test.py:65:25:65:25 | SSA variable e | test.py:66:24:66:40 | ControlFlowNode for Dict | $@ flows to this location and may be exposed to an external user. | test.py:65:25:65:25 | SSA variable e | Stack trace information |
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from flask import Flask, request, make_response
|
from flask import Flask, request, make_response, jsonify
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
|
||||||
@@ -56,3 +56,15 @@ def format_error(msg):
|
|||||||
@app.route('/maybe_xss')
|
@app.route('/maybe_xss')
|
||||||
def maybe_xss():
|
def maybe_xss():
|
||||||
return make_response(request.args.get('name', ''))
|
return make_response(request.args.get('name', ''))
|
||||||
|
|
||||||
|
# BAD
|
||||||
|
@app.route('/bad/jsonify')
|
||||||
|
def bad_jsonify():
|
||||||
|
try:
|
||||||
|
do_computation()
|
||||||
|
except Exception as e: # $ exceptionInfo
|
||||||
|
return jsonify({"error": str(e)})
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run(debug=True)
|
||||||
|
|||||||
Reference in New Issue
Block a user