Files
xiaoxia-saas/.venv-ci-root/Lib/site-packages/bandit/plugins/markupsafe_markup_xss.py
T

119 lines
3.6 KiB
Python

# Copyright (c) 2025 David Salvisberg
#
# SPDX-License-Identifier: Apache-2.0
r"""
============================================
B704: Potential XSS on markupsafe.Markup use
============================================
``markupsafe.Markup`` does not perform any escaping, so passing dynamic
content, like f-strings, variables or interpolated strings will potentially
lead to XSS vulnerabilities, especially if that data was submitted by users.
Instead you should interpolate the resulting ``markupsafe.Markup`` object,
which will perform escaping, or use ``markupsafe.escape``.
**Config Options:**
This plugin allows you to specify additional callable that should be treated
like ``markupsafe.Markup``. By default we recognize ``flask.Markup`` as
an alias, but there are other subclasses or similar classes in the wild
that you may wish to treat the same.
Additionally there is a whitelist for callable names, whose result may
be safely passed into ``markupsafe.Markup``. This is useful for escape
functions like e.g. ``bleach.clean`` which don't themselves return
``markupsafe.Markup``, so they need to be wrapped. Take care when using
this setting, since incorrect use may introduce false negatives.
These two options can be set in a shared configuration section
`markupsafe_xss`.
.. code-block:: yaml
markupsafe_xss:
# Recognize additional aliases
extend_markup_names:
- webhelpers.html.literal
- my_package.Markup
# Allow the output of these functions to pass into Markup
allowed_calls:
- bleach.clean
- my_package.sanitize
:Example:
.. code-block:: none
>> Issue: [B704:markupsafe_markup_xss] Potential XSS with
``markupsafe.Markup`` detected. Do not use ``Markup``
on untrusted data.
Severity: Medium Confidence: High
CWE: CWE-79 (https://cwe.mitre.org/data/definitions/79.html)
Location: ./examples/markupsafe_markup_xss.py:5:0
4 content = "<script>alert('Hello, world!')</script>"
5 Markup(f"unsafe {content}")
6 flask.Markup("unsafe {}".format(content))
.. seealso::
- https://pypi.org/project/MarkupSafe/
- https://markupsafe.palletsprojects.com/en/stable/escaping/#markupsafe.Markup
- https://cwe.mitre.org/data/definitions/79.html
.. versionadded:: 1.8.3
"""
import ast
import bandit
from bandit.core import issue
from bandit.core import test_properties as test
from bandit.core.utils import get_call_name
def gen_config(name):
if name == "markupsafe_xss":
return {
"extend_markup_names": [],
"allowed_calls": [],
}
@test.takes_config("markupsafe_xss")
@test.checks("Call")
@test.test_id("B704")
def markupsafe_markup_xss(context, config):
qualname = context.call_function_name_qual
if qualname not in ("markupsafe.Markup", "flask.Markup"):
if qualname not in config.get("extend_markup_names", []):
# not a Markup call
return None
args = context.node.args
if not args or isinstance(args[0], ast.Constant):
# both no arguments and a constant are fine
return None
allowed_calls = config.get("allowed_calls", [])
if (
allowed_calls
and isinstance(args[0], ast.Call)
and get_call_name(args[0], context.import_aliases) in allowed_calls
):
# the argument contains a whitelisted call
return None
return bandit.Issue(
severity=bandit.MEDIUM,
confidence=bandit.HIGH,
cwe=issue.Cwe.XSS,
text=f"Potential XSS with ``{qualname}`` detected. Do "
f"not use ``{context.call_function_name}`` on untrusted data.",
)