python-bandit

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Python Bandit Security Scanning

Python Bandit 安全扫描

Bandit is a static analysis tool that finds common security issues in Python code. It processes each file, builds an AST, and runs security-focused plugins against AST nodes. Results are categorized by severity (LOW, MEDIUM, HIGH) and confidence (LOW, MEDIUM, HIGH).
Bandit 是一款用于检测Python代码中常见安全问题的静态分析工具。它会处理每个文件,构建AST(抽象语法树),并针对AST节点运行专注于安全的插件。检测结果会按照严重程度(LOW、MEDIUM、HIGH)和置信度(LOW、MEDIUM、HIGH)进行分类。

Installation

安装

Install the base package or add extras for specific features:
bash
undefined
安装基础包或添加扩展以获取特定功能:
bash
undefined

Base installation

Base installation

pip install bandit
pip install bandit

With TOML config support (pyproject.toml)

With TOML config support (pyproject.toml)

pip install "bandit[toml]"
pip install "bandit[toml]"

With SARIF output (for GitHub Advanced Security)

With SARIF output (for GitHub Advanced Security)

pip install "bandit[sarif]"
pip install "bandit[sarif]"

With baseline support

With baseline support

pip install "bandit[baseline]"

Use the same Python version as the project under scan. Bandit relies on Python's `ast` module, which can only parse code valid for that interpreter version.
pip install "bandit[baseline]"

请使用与待扫描项目相同的Python版本。Bandit依赖Python的`ast`模块,该模块只能解析对应解释器版本支持的有效代码。

Core Usage

核心用法

Scan a full project tree:
bash
bandit -r path/to/project/
Scan with severity filter (report only HIGH):
bash
bandit -r . --severity-level high
扫描整个项目目录:
bash
bandit -r path/to/project/
按严重程度过滤扫描结果(仅报告HIGH级别):
bash
bandit -r . --severity-level high

or shorthand: -lll (high), -ll (medium+), -l (low+)

or shorthand: -lll (high), -ll (medium+), -l (low+)

bandit -r . -lll

**Scan with confidence filter:**

```bash
bandit -r . --confidence-level high
bandit -r . -lll

**按置信度过滤扫描结果:**

```bash
bandit -r . --confidence-level high

shorthand: -iii (high), -ii (medium+), -i (low+)

shorthand: -iii (high), -ii (medium+), -i (low+)


**Target specific test IDs only:**

```bash
bandit -r . -t B105,B106,B107   # hardcoded password checks only
Skip specific test IDs:
bash
bandit -r . -s B101             # skip assert_used (common in tests)
Use a named profile:
bash
bandit examples/*.py -p ShellInjection
Scan from stdin:
bash
cat myfile.py | bandit -
Show N lines of context per finding:
bash
bandit -r . -n 3

**仅针对特定测试ID进行扫描:**

```bash
bandit -r . -t B105,B106,B107   # hardcoded password checks only
跳过特定测试ID:
bash
bandit -r . -s B101             # skip assert_used (common in tests)
使用指定配置文件:
bash
bandit examples/*.py -p ShellInjection
从标准输入读取代码进行扫描:
bash
cat myfile.py | bandit -
显示每个检测结果的N行上下文:
bash
bandit -r . -n 3

Configuration

配置

pyproject.toml (Recommended)

pyproject.toml(推荐)

Centralize Bandit settings alongside other tooling:
toml
[tool.bandit]
exclude_dirs = ["tests", "migrations", "venv"]
skips = ["B101"]          # assert_used — acceptable in test suites
tests = []                # empty = run all (minus skips)
Run with explicit config pointer:
bash
bandit -c pyproject.toml -r .
将Bandit的配置与其他工具的配置集中管理:
toml
[tool.bandit]
exclude_dirs = ["tests", "migrations", "venv"]
skips = ["B101"]          # assert_used — acceptable in test suites
tests = []                # empty = run all (minus skips)
指定配置文件路径运行扫描:
bash
bandit -c pyproject.toml -r .

.bandit (INI — auto-discovered with -r)

.bandit(INI格式 - 使用-r参数时会自动识别)

ini
[bandit]
exclude = tests,migrations
skips = B101,B601
tests = B201,B301
Bandit auto-discovers
.bandit
when invoked with
-r
. No
-c
flag needed.
ini
[bandit]
exclude = tests,migrations
skips = B101,B601
tests = B201,B301
当使用
-r
参数运行Bandit时,会自动识别
.bandit
文件,无需添加
-c
参数。

YAML Config

YAML配置

yaml
exclude_dirs: ['tests', 'path/to/file']
tests: ['B201', 'B301']
skips: ['B101', 'B601']
yaml
exclude_dirs: ['tests', 'path/to/file']
tests: ['B201', 'B301']
skips: ['B101', 'B601']

Override plugin-specific defaults

Override plugin-specific defaults

try_except_pass: check_typed_exception: true

Run: `bandit -c bandit.yaml -r .`
try_except_pass: check_typed_exception: true

运行命令:`bandit -c bandit.yaml -r .`

Generate a Config Template

生成配置模板

bash
bandit-config-generator > bandit.yaml
bash
bandit-config-generator > bandit.yaml

Then edit — remove sections you don't need, adjust defaults

Then edit — remove sections you don't need, adjust defaults

undefined
undefined

Suppressing False Positives

抑制误报

Mark individual lines with
# nosec
to suppress all findings:
python
self.process = subprocess.Popen('/bin/echo', shell=True)  # nosec
Suppress specific test IDs only (preferred — avoids hiding future issues):
python
self.process = subprocess.Popen('/bin/ls *', shell=True)  # nosec B602, B607
Use the full test name as an alternative to the ID:
python
assert yaml.load("{}") == []  # nosec assert_used
Always add a comment explaining why the suppression is justified.
在单独代码行添加
# nosec
标记以抑制所有检测结果:
python
self.process = subprocess.Popen('/bin/echo', shell=True)  # nosec
仅抑制特定测试ID的结果(推荐方式 - 避免隐藏未来出现的问题):
python
self.process = subprocess.Popen('/bin/ls *', shell=True)  # nosec B602, B607
也可以使用完整的测试名称替代测试ID:
python
assert yaml.load("{}") == []  # nosec assert_used
请务必添加注释说明抑制结果的合理原因。

Output Formats

输出格式

bash
bandit -r . -f json -o report.json      # JSON (required for baseline)
bandit -r . -f sarif -o report.sarif    # SARIF (GitHub Advanced Security)
bandit -r . -f csv -o report.csv        # CSV
bandit -r . -f xml -o report.xml        # XML
bandit -r . -f html -o report.html      # HTML
bandit -r . -f screen                   # Terminal (default)
bandit -r . -f yaml -o report.yaml      # YAML
bash
bandit -r . -f json -o report.json      # JSON (required for baseline)
bandit -r . -f sarif -o report.sarif    # SARIF (GitHub Advanced Security)
bandit -r . -f csv -o report.csv        # CSV
bandit -r . -f xml -o report.xml        # XML
bandit -r . -f html -o report.html      # HTML
bandit -r . -f screen                   # Terminal (default)
bandit -r . -f yaml -o report.yaml      # YAML

Baseline Workflow

基线工作流

Use baselines to track only new issues, ignoring pre-existing findings:
bash
undefined
使用基线功能仅跟踪新出现的问题,忽略已存在的检测结果:
bash
undefined

1. Generate a baseline from the current state of the codebase

1. 根据当前代码库状态生成基线

bandit -r . -f json -o .bandit-baseline.json
bandit -r . -f json -o .bandit-baseline.json

2. Commit the baseline to version control

2. 将基线文件提交至版本控制系统

git add .bandit-baseline.json
git add .bandit-baseline.json

3. Future scans compare against the baseline

3. 后续扫描将与基线进行对比

bandit -r . -b .bandit-baseline.json

Useful when adopting Bandit on an existing codebase — block only newly introduced issues.
bandit -r . -b .bandit-baseline.json

此功能在现有代码库中引入Bandit时非常有用 — 仅阻止新引入的问题。

Critical Plugin Categories

关键插件类别

Bandit test IDs follow a group scheme:
RangeCategory
B1xxMiscellaneous
B2xxApp/framework misconfiguration
B3xxBlacklisted calls
B4xxBlacklisted imports
B5xxCryptography
B6xxInjection
B7xxXSS
Bandit的测试ID遵循分组规则:
范围类别
B1xx其他杂项
B2xx应用/框架配置错误
B3xx黑名单函数调用
B4xx黑名单导入
B5xx加密相关
B6xx注入攻击
B7xxXSS攻击

High-Priority Checks to Always Enforce

需始终强制执行的高优先级检查

Hardcoded secrets (B105, B106, B107) — passwords assigned to variables, passed as function arguments, or set as default parameters.
Injection (B602, B608) — shell injection via
subprocess
with
shell=True
, SQL injection via hardcoded SQL string construction.
Weak cryptography (B324, B501–B505) — MD5/SHA1 use, disabled TLS certificate validation, weak SSL versions, short cryptographic keys.
Unsafe deserialization (B301, B302, B303, B304)
pickle
,
marshal
,
yaml.load()
without
Loader
.
Template injection (B701, B703, B704) — Jinja2 autoescape disabled, Django
mark_safe
, MarkupSafe XSS.
硬编码密钥(B105、B106、B107) — 赋值给变量、作为函数参数传递或设为默认参数的密码。
注入攻击(B602、B608) — 通过
subprocess
配合
shell=True
实现的Shell注入,通过硬编码SQL字符串构造实现的SQL注入。
弱加密(B324、B501–B505) — 使用MD5/SHA1、禁用TLS证书验证、弱SSL版本、短加密密钥。
不安全的反序列化(B301、B302、B303、B304) — 使用
pickle
marshal
、未指定
Loader
yaml.load()
模板注入(B701、B703、B704) — Jinja2自动转义禁用、Django的
mark_safe
、MarkupSafe XSS。

Common Findings and Fixes

常见检测结果及修复方案

B101 — assert_used
Asserts are stripped in optimized mode (
python -O
). Never use
assert
for security-critical checks.
python
undefined
B101 — 使用assert
在优化模式(
python -O
)下,assert语句会被移除。绝不要将assert用于安全相关的关键检查。
python
undefined

Bad

错误写法

assert user.is_admin, "Not authorized"
assert user.is_admin, "Not authorized"

Good

正确写法

if not user.is_admin: raise PermissionError("Not authorized")

**B105/B106/B107 — Hardcoded password**

```python
if not user.is_admin: raise PermissionError("Not authorized")

**B105/B106/B107 — 硬编码密码**

```python

Bad

错误写法

password = "hunter2" connect(password="secret")
password = "hunter2" connect(password="secret")

Good — read from environment or secrets manager

正确写法 — 从环境变量或密钥管理工具中读取

import os password = os.environ["DB_PASSWORD"]

**B324 — Weak hash (MD5/SHA1)**

```python
import os password = os.environ["DB_PASSWORD"]

**B324 — 弱哈希算法(MD5/SHA1)**

```python

Bad

错误写法

import hashlib hashlib.md5(data)
import hashlib hashlib.md5(data)

Good — use SHA-256 or higher for security contexts

正确写法 — 安全场景下使用SHA-256或更高版本

hashlib.sha256(data)
hashlib.sha256(data)

If MD5 is for non-security use (checksums), suppress with comment:

如果MD5用于非安全场景(如校验和),可添加注释抑制告警:

hashlib.md5(data).hexdigest() # nosec B324 — used for cache key, not security

**B506 — yaml.load()**

```python
hashlib.md5(data).hexdigest() # nosec B324 — 用于缓存键,非安全用途

**B506 — 使用yaml.load()**

```python

Bad — arbitrary code execution risk

错误写法 — 存在任意代码执行风险

import yaml yaml.load(data)
import yaml yaml.load(data)

Good

正确写法

yaml.safe_load(data)
yaml.safe_load(data)

or

yaml.load(data, Loader=yaml.SafeLoader)

**B602 — subprocess with shell=True**

```python
yaml.load(data, Loader=yaml.SafeLoader)

**B602 — subprocess配合shell=True**

```python

Bad — shell injection vector

错误写法 — 存在Shell注入风险

subprocess.Popen(user_input, shell=True)
subprocess.Popen(user_input, shell=True)

Good — pass args as a list, avoid shell

正确写法 — 将参数以列表形式传递,避免使用shell

subprocess.Popen(["ls", "-l", path])

**B608 — Hardcoded SQL**

```python
subprocess.Popen(["ls", "-l", path])

**B608 — 硬编码SQL语句**

```python

Bad

错误写法

query = "SELECT * FROM users WHERE name = '" + name + "'"
query = "SELECT * FROM users WHERE name = '" + name + "'"

Good — use parameterized queries

正确写法 — 使用参数化查询

cursor.execute("SELECT * FROM users WHERE name = ?", (name,))

**B501 — No certificate validation**

```python
cursor.execute("SELECT * FROM users WHERE name = ?", (name,))

**B501 — 未验证证书**

```python

Bad

错误写法

requests.get(url, verify=False)
requests.get(url, verify=False)

Good

正确写法

requests.get(url) # verify=True by default requests.get(url, verify="/path/to/ca-bundle.crt")
undefined
requests.get(url) # 默认开启verify=True requests.get(url, verify="/path/to/ca-bundle.crt")
undefined

Severity Triage Workflow

严重程度分级处理流程

  1. Run Bandit with JSON output format and save results to a file (see Output Formats section above).
  2. Fix all HIGH severity + HIGH confidence findings first — these are near-certain vulnerabilities.
  3. Evaluate MEDIUM severity findings for false positives; suppress with documented
    # nosec
    if safe.
  4. Decide team policy on LOW severity — consider skipping known false-positive-heavy tests via
    skips
    .
  5. Establish a baseline for legacy codebases to avoid alert fatigue during adoption.
  1. 使用JSON格式运行Bandit并将结果保存至文件(详见上文输出格式部分)。
  2. 优先修复所有严重级别为HIGH且置信度为HIGH的结果 — 这些几乎可以确定是漏洞。
  3. 评估严重级别为MEDIUM的结果是否为误报;若确认安全,添加带说明的
    # nosec
    标记进行抑制。
  4. 针对严重级别为LOW的结果制定团队策略 — 可考虑通过
    skips
    参数跳过已知误报率高的测试项。
  5. 为遗留代码库建立基线,避免在引入工具时产生过多告警导致疲劳。

Additional Resources

额外资源

  • references/plugin-reference.md
    — Complete B-code listing with severity, description, and fix pattern per plugin
  • references/ci-cd-integration.md
    — Pre-commit hooks, GitHub Actions, and baseline automation workflows
  • references/plugin-reference.md
    — 完整的B代码列表,包含每个插件的严重级别、描述及修复方案
  • references/ci-cd-integration.md
    — 预提交钩子、GitHub Actions及基线自动化工作流的相关内容