135 lines
5.7 KiB
Python
135 lines
5.7 KiB
Python
#
|
|
# Copyright 2014 Hewlett-Packard Development Company, L.P.
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
r"""
|
|
==========================================
|
|
B701: Test for not auto escaping in jinja2
|
|
==========================================
|
|
|
|
Jinja2 is a Python HTML templating system. It is typically used to build web
|
|
applications, though appears in other places well, notably the Ansible
|
|
automation system. When configuring the Jinja2 environment, the option to use
|
|
autoescaping on input can be specified. When autoescaping is enabled, Jinja2
|
|
will filter input strings to escape any HTML content submitted via template
|
|
variables. Without escaping HTML input the application becomes vulnerable to
|
|
Cross Site Scripting (XSS) attacks.
|
|
|
|
Unfortunately, autoescaping is False by default. Thus this plugin test will
|
|
warn on omission of an autoescape setting, as well as an explicit setting of
|
|
false. A HIGH severity warning is generated in either of these scenarios.
|
|
|
|
:Example:
|
|
|
|
.. code-block:: none
|
|
|
|
>> Issue: Using jinja2 templates with autoescape=False is dangerous and can
|
|
lead to XSS. Use autoescape=True to mitigate XSS vulnerabilities.
|
|
Severity: High Confidence: High
|
|
CWE: CWE-94 (https://cwe.mitre.org/data/definitions/94.html)
|
|
Location: ./examples/jinja2_templating.py:11
|
|
10 templateEnv = jinja2.Environment(autoescape=False,
|
|
loader=templateLoader)
|
|
11 Environment(loader=templateLoader,
|
|
12 load=templateLoader,
|
|
13 autoescape=False)
|
|
14
|
|
|
|
>> Issue: By default, jinja2 sets autoescape to False. Consider using
|
|
autoescape=True or use the select_autoescape function to mitigate XSS
|
|
vulnerabilities.
|
|
Severity: High Confidence: High
|
|
CWE: CWE-94 (https://cwe.mitre.org/data/definitions/94.html)
|
|
Location: ./examples/jinja2_templating.py:15
|
|
14
|
|
15 Environment(loader=templateLoader,
|
|
16 load=templateLoader)
|
|
17
|
|
18 Environment(autoescape=select_autoescape(['html', 'htm', 'xml']),
|
|
19 loader=templateLoader)
|
|
|
|
|
|
.. seealso::
|
|
|
|
- `OWASP XSS <https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)>`__
|
|
- https://realpython.com/primer-on-jinja-templating/
|
|
- https://jinja.palletsprojects.com/en/2.11.x/api/#autoescaping
|
|
- https://security.openstack.org/guidelines/dg_cross-site-scripting-xss.html
|
|
- https://cwe.mitre.org/data/definitions/94.html
|
|
|
|
.. versionadded:: 0.10.0
|
|
|
|
.. versionchanged:: 1.7.3
|
|
CWE information added
|
|
|
|
"""
|
|
import ast
|
|
|
|
import bandit
|
|
from bandit.core import issue
|
|
from bandit.core import test_properties as test
|
|
|
|
|
|
@test.checks("Call")
|
|
@test.test_id("B701")
|
|
def jinja2_autoescape_false(context):
|
|
# check type just to be safe
|
|
if isinstance(context.call_function_name_qual, str):
|
|
qualname_list = context.call_function_name_qual.split(".")
|
|
func = qualname_list[-1]
|
|
if "jinja2" in qualname_list and func == "Environment":
|
|
for node in ast.walk(context.node):
|
|
if isinstance(node, ast.keyword):
|
|
# definite autoescape = False
|
|
if getattr(node, "arg", None) == "autoescape" and (
|
|
getattr(node.value, "id", None) == "False"
|
|
or getattr(node.value, "value", None) is False
|
|
):
|
|
return bandit.Issue(
|
|
severity=bandit.HIGH,
|
|
confidence=bandit.HIGH,
|
|
cwe=issue.Cwe.CODE_INJECTION,
|
|
text="Using jinja2 templates with autoescape="
|
|
"False is dangerous and can lead to XSS. "
|
|
"Use autoescape=True or use the "
|
|
"select_autoescape function to mitigate XSS "
|
|
"vulnerabilities.",
|
|
)
|
|
# found autoescape
|
|
if getattr(node, "arg", None) == "autoescape":
|
|
value = getattr(node, "value", None)
|
|
if (
|
|
getattr(value, "id", None) == "True"
|
|
or getattr(value, "value", None) is True
|
|
):
|
|
return
|
|
# Check if select_autoescape function is used.
|
|
elif isinstance(value, ast.Call) and (
|
|
getattr(value.func, "attr", None)
|
|
== "select_autoescape"
|
|
or getattr(value.func, "id", None)
|
|
== "select_autoescape"
|
|
):
|
|
return
|
|
else:
|
|
return bandit.Issue(
|
|
severity=bandit.HIGH,
|
|
confidence=bandit.MEDIUM,
|
|
cwe=issue.Cwe.CODE_INJECTION,
|
|
text="Using jinja2 templates with autoescape="
|
|
"False is dangerous and can lead to XSS. "
|
|
"Ensure autoescape=True or use the "
|
|
"select_autoescape function to mitigate "
|
|
"XSS vulnerabilities.",
|
|
)
|
|
# We haven't found a keyword named autoescape, indicating default
|
|
# behavior
|
|
return bandit.Issue(
|
|
severity=bandit.HIGH,
|
|
confidence=bandit.HIGH,
|
|
cwe=issue.Cwe.CODE_INJECTION,
|
|
text="By default, jinja2 sets autoescape to False. Consider "
|
|
"using autoescape=True or use the select_autoescape "
|
|
"function to mitigate XSS vulnerabilities.",
|
|
)
|