Skip to content

Commit

Permalink
Merge branch 'main' into missing-metric-in-report
Browse files Browse the repository at this point in the history
  • Loading branch information
lukehinds authored Feb 19, 2025
2 parents de4b9f1 + c58c00a commit e411eaf
Show file tree
Hide file tree
Showing 27 changed files with 356 additions and 157 deletions.
5 changes: 4 additions & 1 deletion .github/ISSUE_TEMPLATE/bug-report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ body:
label: Bandit version
description: Run "bandit --version" if unsure of version number
options:
- 1.7.10 (Default)
- 1.8.2 (Default)
- 1.8.1
- 1.8.0
- 1.7.10
- 1.7.9
- 1.7.8
- 1.7.7
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/build-publish-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
ref: ${{ github.event_name == 'release' && github.ref || env.RELEASE_TAG }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3
uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3

- name: Log in to GitHub Container Registry
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
Expand All @@ -41,7 +41,7 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}

- name: Install Cosign
uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0
uses: sigstore/cosign-installer@c56c2d3e59e4281cc41dea2217323ba5694b171e # v3.8.0
with:
cosign-release: 'v2.2.2'

Expand All @@ -51,7 +51,7 @@ jobs:
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6
with:
context: .
file: ./docker/Dockerfile
Expand Down
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ repos:
- id: reorder-python-imports
args: [--application-directories, '.:src', --py38-plus]
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 24.10.0
rev: 25.1.0
hooks:
- id: black
args: [--line-length=79, --target-version=py38]
- repo: https://github.com/asottile/pyupgrade
rev: v3.19.0
rev: v3.19.1
hooks:
- id: pyupgrade
args: [--py38-plus]
Expand Down
7 changes: 6 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,12 @@ The development of Bandit is made possible by the following sponsors:
:width: 100%
:class: borderless

* - .. image:: https://github.githubassets.com/assets/tidelift-8cea37dea8fc.svg
* - .. image:: https://avatars.githubusercontent.com/u/34240465?s=200&v=4
:target: https://opensource.mercedes-benz.com/
:alt: Mercedes-Benz
:width: 88

- .. image:: https://github.githubassets.com/assets/tidelift-8cea37dea8fc.svg
:target: https://tidelift.com/lifter/search/pypi/bandit
:alt: Tidelift
:width: 88
Expand Down
38 changes: 17 additions & 21 deletions bandit/blacklists/calls.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@
| | | - random.uniform | |
| | | - random.triangular | |
| | | - random.randbytes | |
| | | - random.randrange | |
| | | - random.sample | |
| | | - random.getrandbits | |
+------+---------------------+------------------------------------+-----------+
B312: telnetlib
Expand All @@ -219,7 +222,7 @@
| B312 | telnetlib | - telnetlib.\* | High |
+------+---------------------+------------------------------------+-----------+
B313 - B320: XML
B313 - B319: XML
----------------
Most of this is based off of Christian Heimes' work on defusedxml:
Expand Down Expand Up @@ -256,6 +259,15 @@
| B319 | xml_bad_pulldom | - xml.dom.pulldom.parse | Medium |
| | | - xml.dom.pulldom.parseString | |
+------+---------------------+------------------------------------+-----------+
B320: xml_bad_etree
-------------------
The check for this call has been removed.
+------+---------------------+------------------------------------+-----------+
| ID | Name | Calls | Severity |
+======+=====================+====================================+===========+
| B320 | xml_bad_etree | - lxml.etree.parse | Medium |
| | | - lxml.etree.fromstring | |
| | | - lxml.etree.RestrictedElement | |
Expand Down Expand Up @@ -506,6 +518,9 @@ def gen_blacklist():
"random.uniform",
"random.triangular",
"random.randbytes",
"random.sample",
"random.randrange",
"random.getrandbits",
],
"Standard pseudo-random generators are not suitable for "
"security/cryptographic purposes.",
Expand Down Expand Up @@ -615,26 +630,7 @@ def gen_blacklist():
)
)

sets.append(
utils.build_conf_dict(
"xml_bad_etree",
"B320",
issue.Cwe.IMPROPER_INPUT_VALIDATION,
[
"lxml.etree.parse",
"lxml.etree.fromstring",
"lxml.etree.RestrictedElement",
"lxml.etree.GlobalParserTLS",
"lxml.etree.getDefaultParser",
"lxml.etree.check_docinfo",
],
(
"Using {name} to parse untrusted XML data is known to be "
"vulnerable to XML attacks. Replace {name} with its "
"defusedxml equivalent function."
),
)
)
# skipped B320 as the check for a call to lxml.etree has been removed

# end of XML tests

Expand Down
19 changes: 4 additions & 15 deletions bandit/blacklists/imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@
B410: import_lxml
-----------------
This import blacklist has been removed. The information here has been
left for historical purposes.
Using various methods to parse untrusted XML data is known to be vulnerable to
XML attacks. Replace vulnerable imports with the equivalent defusedxml package.
Expand Down Expand Up @@ -297,11 +300,6 @@ def gen_blacklist():
"defusedxml package, or make sure defusedxml.defuse_stdlib() "
"is called."
)
lxml_msg = (
"Using {name} to parse untrusted XML data is known to be "
"vulnerable to XML attacks. Replace {name} with the "
"equivalent defusedxml package."
)

sets.append(
utils.build_conf_dict(
Expand Down Expand Up @@ -358,16 +356,7 @@ def gen_blacklist():
)
)

sets.append(
utils.build_conf_dict(
"import_lxml",
"B410",
issue.Cwe.IMPROPER_INPUT_VALIDATION,
["lxml"],
lxml_msg,
"LOW",
)
)
# skipped B410 as the check for import_lxml has been removed

sets.append(
utils.build_conf_dict(
Expand Down
4 changes: 4 additions & 0 deletions bandit/core/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,3 +318,7 @@ def filename(self):
@property
def file_data(self):
return self._context.get("file_data")

@property
def import_aliases(self):
return self._context.get("import_aliases")
7 changes: 5 additions & 2 deletions bandit/core/extension_loader.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
#
# SPDX-License-Identifier: Apache-2.0
import logging
import sys

from stevedore import extension

from bandit.core import utils

LOG = logging.getLogger(__name__)


class Manager:
# These IDs are for bandit built in tests
Expand Down Expand Up @@ -84,11 +87,11 @@ def validate_profile(self, profile):
"""Validate that everything in the configured profiles looks good."""
for inc in profile["include"]:
if not self.check_id(inc):
raise ValueError(f"Unknown test found in profile: {inc}")
LOG.warning(f"Unknown test found in profile: {inc}")

for exc in profile["exclude"]:
if not self.check_id(exc):
raise ValueError(f"Unknown test found in profile: {exc}")
LOG.warning(f"Unknown test found in profile: {exc}")

union = set(profile["include"]) & set(profile["exclude"])
if len(union) > 0:
Expand Down
10 changes: 9 additions & 1 deletion bandit/plugins/general_hardcoded_password.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,9 @@ def hardcoded_password_default(context):
- "token"
- "secrete"
Note: this can be noisy and may generate false positives.
Note: this can be noisy and may generate false positives. We do not
report on None values which can be legitimately used as a default value,
when initializing a function or class.
**Config Options:**
Expand Down Expand Up @@ -242,5 +244,11 @@ def hardcoded_password_default(context):
# go through all (param, value)s and look for candidates
for key, val in zip(context.node.args.args, defs):
if isinstance(key, (ast.Name, ast.arg)):
# Skip if the default value is None
if val is None or (
isinstance(val, (ast.Constant, ast.NameConstant))
and val.value is None
):
continue
if isinstance(val, ast.Str) and RE_CANDIDATES.search(key.arg):
return _report(val.s)
118 changes: 118 additions & 0 deletions bandit/plugins/markupsafe_markup_xss.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# 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.",
)
Loading

0 comments on commit e411eaf

Please sign in to comment.