python.flask.security.injection.raw-html-concat.raw-html-format

Author
unknown
Download Count*
License
Detected user input flowing into a manually constructed HTML string. You may be accidentally bypassing secure methods of rendering HTML by manually constructing HTML and this could create a cross-site scripting vulnerability, which could let attackers steal sensitive user data. To be sure this is safe, check that the HTML is rendered safely. Otherwise, use templates (flask.render_template
) which will safely render HTML instead.
Run Locally
Run in CI
Defintion
rules:
- id: raw-html-format
languages:
- python
severity: WARNING
message: Detected user input flowing into a manually constructed HTML string.
You may be accidentally bypassing secure methods of rendering HTML by
manually constructing HTML and this could create a cross-site scripting
vulnerability, which could let attackers steal sensitive user data. To be
sure this is safe, check that the HTML is rendered safely. Otherwise, use
templates (`flask.render_template`) which will safely render HTML instead.
metadata:
cwe:
- "CWE-79: Improper Neutralization of Input During Web Page Generation
('Cross-site Scripting')"
owasp:
- A07:2017 - Cross-Site Scripting (XSS)
- A03:2021 - Injection
category: security
technology:
- flask
references:
- https://flask.palletsprojects.com/en/2.0.x/security/#cross-site-scripting-xss
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
cwe2022-top25: true
cwe2021-top25: true
subcategory:
- vuln
likelihood: MEDIUM
impact: MEDIUM
confidence: MEDIUM
vulnerability_class:
- Cross-Site-Scripting (XSS)
mode: taint
pattern-sanitizers:
- pattern: jinja2.escape(...)
- pattern: flask.escape(...)
- pattern: flask.render_template("~=/.*\.html", ...)
pattern-sources:
- patterns:
- pattern-either:
- pattern: flask.request.$ANYTHING
- patterns:
- pattern-inside: |
@$APP.route(...)
def $FUNC(..., $ROUTEVAR, ...):
...
- pattern: $ROUTEVAR
pattern-sinks:
- patterns:
- pattern-either:
- patterns:
- pattern-either:
- pattern: '"$HTMLSTR" % ...'
- pattern: '"$HTMLSTR".format(...)'
- pattern: '"$HTMLSTR" + ...'
- pattern: f"$HTMLSTR{...}..."
- patterns:
- pattern-inside: |
$HTML = "$HTMLSTR"
...
- pattern-either:
- pattern: $HTML % ...
- pattern: $HTML.format(...)
- pattern: $HTML + ...
- metavariable-pattern:
metavariable: $HTMLSTR
language: generic
pattern: <$TAG ...
Examples
raw-html-concat.py
import os
import flask
import hashlib
app = flask.Flask(__name__)
@app.route("/route_param/<route_param>")
def route_param(route_param):
print("blah")
# ruleid:raw-html-format
return "<a href='%s'>Click me!</a>" % route_param
@app.route("/route_param_ok/<route_param>")
def route_param_ok(route_param):
print("blah")
# ok: raw-html-format
return "<a href='https://example.com'>Click me!</a>"
@app.route("/route_param_format/<route_param>")
def route_param_format(route_param):
print("blah")
# ruleid:raw-html-format
return "<a href='{}'>Click me!</a>".format(route_param)
@app.route("/route_param_percent_format/<route_param>")
def route_param_percent_format(route_param):
print("blah")
# ruleid:raw-html-format
return "<a href='%s'>Click me!</a>" % route_param
@app.route("/get_param_inline", methods=["GET"])
def get_param_inline():
# ruleid:raw-html-format
return "<a href='%s'>Click me!</a>" % flask.request.args.get("param")
@app.route("/get_param_inline_concat", methods=["GET"])
def get_param_inline_concat():
# ruleid:raw-html-format
return "<a href='" + flask.request.args.get("param") + "'>Click me!</a>"
@app.route("/get_param_concat", methods=["GET"])
def get_param_concat():
param = flask.request.args.get("param")
# ruleid:raw-html-format
return "<a href='" + param + "'>Click me!</a>"
@app.route("/get_param_format", methods=["GET"])
def get_param_format():
param = flask.request.args.get("param")
# ruleid:raw-html-format
return "<a href='{}'>Click me!</a>".format(param)
@app.route("/get_param_percent_format", methods=["GET"])
def get_param_percent_format():
param = flask.request.args.get("param")
# ruleid:raw-html-format
return "<a href='%s'>Click me!</a>" % (param,)
@app.route("/post_param_branch", methods=["POST"])
def post_param_branch():
param = flask.request.form['param']
if True:
# ruleid:raw-html-format
return "<a href='%s'>Click me!</a>" % param
# Real world example
@app.route('/models/<model>')
def load_model(model):
# ruleid:raw-html-format
htmlpage = '''
<body style='margin : 0px; overflow: hidden;'>
<scene-tag embedded arjs>
<marker-tag id="memarker" type="pattern" url="../static/patterns/pattern-kanji_qr.patt" vidhandler>
<entity model="obj: url(../static/models/{}.obj); mtl: url(../static/models/{}.mtl)"> </entity>
</marker-tag>
</scene-tag>
</body>
'''.format(model,model)
return htmlpage
@app.route("/ok")
def ok():
# ok: raw-html-format
return "<a href='https://example.com'>Click me!</a>"
Short Link: https://sg.run/Pb7e