Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ private import semmle.python.Concepts
private import semmle.python.frameworks.data.ModelsAsData
private import semmle.python.dataflow.new.RemoteFlowSources
private import semmle.python.dataflow.new.BarrierGuards
private import semmle.python.ApiGraphs

/**
* Provides default sources, sinks and sanitizers for detecting
Expand Down Expand Up @@ -91,4 +92,15 @@ module ReflectedXss {
class SanitizerFromModel extends Sanitizer {
SanitizerFromModel() { ModelOutput::barrierNode(this, ["html-injection", "js-injection"]) }
}

/**
* A call to `json.dumps()`, considered as a sanitizer.
* The output of json.dumps is JSON-formatted data typically returned
* with application/json Content-Type, which browsers do not render as HTML.
*/
class JsonDumpsSanitizer extends Sanitizer {
JsonDumpsSanitizer() {
this = API::moduleImport("json").getMember("dumps").getACall()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import json
from flask import Flask, request, make_response

app = Flask(__name__)


@app.route("/api/data")
def json_api_response():
"""json.dumps output is safe - JSON-encoded data is not rendered as HTML."""
user_input = request.args.get("data", "")
result = json.dumps({"input": user_input})
return make_response(result, 200, {"Content-Type": "application/json"}) # Safe


@app.route("/unsafe")
def unsafe_html_response():
"""Without json.dumps, user input in HTML response is unsafe."""
user_input = request.args.get("data", "")
return make_response("<html>" + user_input + "</html>") # $ Alert
Loading