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)进行分类。
Install the base package or add extras for specific features:
Base installation
Base installation
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`模块,该模块只能解析对应解释器版本支持的有效代码。
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:
**仅针对特定测试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行上下文:
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
when invoked with
. No
flag needed.
ini
[bandit]
exclude = tests,migrations
skips = B101,B601
tests = B201,B301
当使用
参数运行Bandit时,会自动识别
文件,无需添加
参数。
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
Suppressing False Positives
抑制误报
Mark individual lines with
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.
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
请务必添加注释说明抑制结果的合理原因。
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
Use baselines to track only new issues, ignoring pre-existing findings:
使用基线功能仅跟踪新出现的问题,忽略已存在的检测结果:
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:
| Range | Category |
|---|
| B1xx | Miscellaneous |
| B2xx | App/framework misconfiguration |
| B3xx | Blacklisted calls |
| B4xx | Blacklisted imports |
| B5xx | Cryptography |
| B6xx | Injection |
| B7xx | XSS |
Bandit的测试ID遵循分组规则:
| 范围 | 类别 |
|---|
| B1xx | 其他杂项 |
| B2xx | 应用/框架配置错误 |
| B3xx | 黑名单函数调用 |
| B4xx | 黑名单导入 |
| B5xx | 加密相关 |
| B6xx | 注入攻击 |
| B7xx | XSS攻击 |
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
with
, 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) —
,
,
without
.
Template injection (B701, B703, B704) — Jinja2 autoescape disabled, Django
, MarkupSafe XSS.
硬编码密钥(B105、B106、B107) — 赋值给变量、作为函数参数传递或设为默认参数的密码。
注入攻击(B602、B608) — 通过
配合
实现的Shell注入,通过硬编码SQL字符串构造实现的SQL注入。
弱加密(B324、B501–B505) — 使用MD5/SHA1、禁用TLS证书验证、弱SSL版本、短加密密钥。
不安全的反序列化(B301、B302、B303、B304) — 使用
、
、未指定
的
。
模板注入(B701、B703、B704) — Jinja2自动转义禁用、Django的
、MarkupSafe XSS。
Common Findings and Fixes
常见检测结果及修复方案
B101 — assert_used
Asserts are stripped in optimized mode (
). Never use
for security-critical checks.
B101 — 使用assert
在优化模式(
)下,assert语句会被移除。绝不要将assert用于安全相关的关键检查。
assert user.is_admin, "Not authorized"
assert user.is_admin, "Not authorized"
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
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
import hashlib
hashlib.md5(data)
import hashlib
hashlib.md5(data)
Good — use SHA-256 or higher for security contexts
正确写法 — 安全场景下使用SHA-256或更高版本
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)
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
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
requests.get(url, verify=False)
requests.get(url, verify=False)
requests.get(url) # verify=True by default
requests.get(url, verify="/path/to/ca-bundle.crt")
requests.get(url) # 默认开启verify=True
requests.get(url, verify="/path/to/ca-bundle.crt")
Severity Triage Workflow
严重程度分级处理流程
- Run Bandit with JSON output format and save results to a file (see Output Formats section above).
- Fix all HIGH severity + HIGH confidence findings first — these are near-certain vulnerabilities.
- Evaluate MEDIUM severity findings for false positives; suppress with documented if safe.
- Decide team policy on LOW severity — consider skipping known false-positive-heavy tests via .
- Establish a baseline for legacy codebases to avoid alert fatigue during adoption.
- 使用JSON格式运行Bandit并将结果保存至文件(详见上文输出格式部分)。
- 优先修复所有严重级别为HIGH且置信度为HIGH的结果 — 这些几乎可以确定是漏洞。
- 评估严重级别为MEDIUM的结果是否为误报;若确认安全,添加带说明的标记进行抑制。
- 针对严重级别为LOW的结果制定团队策略 — 可考虑通过参数跳过已知误报率高的测试项。
- 为遗留代码库建立基线,避免在引入工具时产生过多告警导致疲劳。
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及基线自动化工作流的相关内容