jinja2_templates.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. #
  2. # Copyright 2014 Hewlett-Packard Development Company, L.P.
  3. #
  4. # SPDX-License-Identifier: Apache-2.0
  5. r"""
  6. ==========================================
  7. B701: Test for not auto escaping in jinja2
  8. ==========================================
  9. Jinja2 is a Python HTML templating system. It is typically used to build web
  10. applications, though appears in other places well, notably the Ansible
  11. automation system. When configuring the Jinja2 environment, the option to use
  12. autoescaping on input can be specified. When autoescaping is enabled, Jinja2
  13. will filter input strings to escape any HTML content submitted via template
  14. variables. Without escaping HTML input the application becomes vulnerable to
  15. Cross Site Scripting (XSS) attacks.
  16. Unfortunately, autoescaping is False by default. Thus this plugin test will
  17. warn on omission of an autoescape setting, as well as an explicit setting of
  18. false. A HIGH severity warning is generated in either of these scenarios.
  19. :Example:
  20. .. code-block:: none
  21. >> Issue: Using jinja2 templates with autoescape=False is dangerous and can
  22. lead to XSS. Use autoescape=True to mitigate XSS vulnerabilities.
  23. Severity: High Confidence: High
  24. CWE: CWE-94 (https://cwe.mitre.org/data/definitions/94.html)
  25. Location: ./examples/jinja2_templating.py:11
  26. 10 templateEnv = jinja2.Environment(autoescape=False,
  27. loader=templateLoader)
  28. 11 Environment(loader=templateLoader,
  29. 12 load=templateLoader,
  30. 13 autoescape=False)
  31. 14
  32. >> Issue: By default, jinja2 sets autoescape to False. Consider using
  33. autoescape=True or use the select_autoescape function to mitigate XSS
  34. vulnerabilities.
  35. Severity: High Confidence: High
  36. CWE: CWE-94 (https://cwe.mitre.org/data/definitions/94.html)
  37. Location: ./examples/jinja2_templating.py:15
  38. 14
  39. 15 Environment(loader=templateLoader,
  40. 16 load=templateLoader)
  41. 17
  42. 18 Environment(autoescape=select_autoescape(['html', 'htm', 'xml']),
  43. 19 loader=templateLoader)
  44. .. seealso::
  45. - `OWASP XSS <https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)>`_
  46. - https://realpython.com/primer-on-jinja-templating/
  47. - https://jinja.palletsprojects.com/en/2.11.x/api/#autoescaping
  48. - https://security.openstack.org/guidelines/dg_cross-site-scripting-xss.html
  49. - https://cwe.mitre.org/data/definitions/94.html
  50. .. versionadded:: 0.10.0
  51. .. versionchanged:: 1.7.3
  52. CWE information added
  53. """
  54. import ast
  55. import bandit
  56. from bandit.core import issue
  57. from bandit.core import test_properties as test
  58. @test.checks("Call")
  59. @test.test_id("B701")
  60. def jinja2_autoescape_false(context):
  61. # check type just to be safe
  62. if isinstance(context.call_function_name_qual, str):
  63. qualname_list = context.call_function_name_qual.split(".")
  64. func = qualname_list[-1]
  65. if "jinja2" in qualname_list and func == "Environment":
  66. for node in ast.walk(context.node):
  67. if isinstance(node, ast.keyword):
  68. # definite autoescape = False
  69. if getattr(node, "arg", None) == "autoescape" and (
  70. getattr(node.value, "id", None) == "False"
  71. or getattr(node.value, "value", None) is False
  72. ):
  73. return bandit.Issue(
  74. severity=bandit.HIGH,
  75. confidence=bandit.HIGH,
  76. cwe=issue.Cwe.CODE_INJECTION,
  77. text="Using jinja2 templates with autoescape="
  78. "False is dangerous and can lead to XSS. "
  79. "Use autoescape=True or use the "
  80. "select_autoescape function to mitigate XSS "
  81. "vulnerabilities.",
  82. )
  83. # found autoescape
  84. if getattr(node, "arg", None) == "autoescape":
  85. value = getattr(node, "value", None)
  86. if (
  87. getattr(value, "id", None) == "True"
  88. or getattr(value, "value", None) is True
  89. ):
  90. return
  91. # Check if select_autoescape function is used.
  92. elif isinstance(value, ast.Call) and (
  93. getattr(value.func, "attr", None)
  94. == "select_autoescape"
  95. or getattr(value.func, "id", None)
  96. == "select_autoescape"
  97. ):
  98. return
  99. else:
  100. return bandit.Issue(
  101. severity=bandit.HIGH,
  102. confidence=bandit.MEDIUM,
  103. cwe=issue.Cwe.CODE_INJECTION,
  104. text="Using jinja2 templates with autoescape="
  105. "False is dangerous and can lead to XSS. "
  106. "Ensure autoescape=True or use the "
  107. "select_autoescape function to mitigate "
  108. "XSS vulnerabilities.",
  109. )
  110. # We haven't found a keyword named autoescape, indicating default
  111. # behavior
  112. return bandit.Issue(
  113. severity=bandit.HIGH,
  114. confidence=bandit.HIGH,
  115. cwe=issue.Cwe.CODE_INJECTION,
  116. text="By default, jinja2 sets autoescape to False. Consider "
  117. "using autoescape=True or use the select_autoescape "
  118. "function to mitigate XSS vulnerabilities.",
  119. )