python-bandit
Original:🇺🇸 English
Translated
This skill should be used when the user asks to "scan Python code for security issues", "set up Bandit", "configure bandit security linting", "fix bandit warnings", or needs guidance on Python static security analysis with Bandit.
3installs
Added on
NPX Install
npx skill4agent add the-perfect-developer/the-perfect-opencode python-banditTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →Python Bandit Security Scanning
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).
Installation
Install the base package or add extras for specific features:
bash
# Base installation
pip install bandit
# With TOML config support (pyproject.toml)
pip install "bandit[toml]"
# With SARIF output (for GitHub Advanced Security)
pip install "bandit[sarif]"
# With baseline support
pip install "bandit[baseline]"Use the same Python version as the project under scan. Bandit relies on Python's module, which can only parse code valid for that interpreter version.
astCore 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
# or shorthand: -lll (high), -ll (medium+), -l (low+)
bandit -r . -lllScan with confidence filter:
bash
bandit -r . --confidence-level high
# shorthand: -iii (high), -ii (medium+), -i (low+)Target specific test IDs only:
bash
bandit -r . -t B105,B106,B107 # hardcoded password checks onlySkip specific test IDs:
bash
bandit -r . -s B101 # skip assert_used (common in tests)Use a named profile:
bash
bandit examples/*.py -p ShellInjectionScan from stdin:
bash
cat myfile.py | bandit -Show N lines of context per finding:
bash
bandit -r . -n 3Configuration
pyproject.toml (Recommended)
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 (INI — auto-discovered with -r)
ini
[bandit]
exclude = tests,migrations
skips = B101,B601
tests = B201,B301Bandit auto-discovers when invoked with . No flag needed.
.bandit-r-cYAML Config
yaml
exclude_dirs: ['tests', 'path/to/file']
tests: ['B201', 'B301']
skips: ['B101', 'B601']
# Override plugin-specific defaults
try_except_pass:
check_typed_exception: trueRun:
bandit -c bandit.yaml -r .Generate a Config Template
bash
bandit-config-generator > bandit.yaml
# Then edit — remove sections you don't need, adjust defaultsSuppressing False Positives
Mark individual lines with to suppress all findings:
# nosecpython
self.process = subprocess.Popen('/bin/echo', shell=True) # nosecSuppress specific test IDs only (preferred — avoids hiding future issues):
python
self.process = subprocess.Popen('/bin/ls *', shell=True) # nosec B602, B607Use the full test name as an alternative to the ID:
python
assert yaml.load("{}") == [] # nosec assert_usedAlways add a comment explaining why the suppression is justified.
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 # YAMLBaseline Workflow
Use baselines to track only new issues, ignoring pre-existing findings:
bash
# 1. Generate a baseline from the current state of the codebase
bandit -r . -f json -o .bandit-baseline.json
# 2. Commit the baseline to version control
git add .bandit-baseline.json
# 3. Future scans compare against the baseline
bandit -r . -b .bandit-baseline.jsonUseful when adopting Bandit on an existing codebase — block only newly introduced issues.
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 |
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.
subprocessshell=TrueWeak cryptography (B324, B501–B505) — MD5/SHA1 use, disabled TLS certificate validation, weak SSL versions, short cryptographic keys.
Unsafe deserialization (B301, B302, B303, B304) — , , without .
picklemarshalyaml.load()LoaderTemplate injection (B701, B703, B704) — Jinja2 autoescape disabled, Django , MarkupSafe XSS.
mark_safeCommon Findings and Fixes
B101 — assert_used
Asserts are stripped in optimized mode (). Never use for security-critical checks.
python -Oassertpython
# Bad
assert user.is_admin, "Not authorized"
# Good
if not user.is_admin:
raise PermissionError("Not authorized")B105/B106/B107 — Hardcoded password
python
# Bad
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
# Bad
import hashlib
hashlib.md5(data)
# Good — use SHA-256 or higher for security contexts
hashlib.sha256(data)
# If MD5 is for non-security use (checksums), suppress with comment:
hashlib.md5(data).hexdigest() # nosec B324 — used for cache key, not securityB506 — yaml.load()
python
# Bad — arbitrary code execution risk
import yaml
yaml.load(data)
# Good
yaml.safe_load(data)
# or
yaml.load(data, Loader=yaml.SafeLoader)B602 — subprocess with shell=True
python
# Bad — shell injection vector
subprocess.Popen(user_input, shell=True)
# Good — pass args as a list, avoid shell
subprocess.Popen(["ls", "-l", path])B608 — Hardcoded SQL
python
# Bad
query = "SELECT * FROM users WHERE name = '" + name + "'"
# Good — use parameterized queries
cursor.execute("SELECT * FROM users WHERE name = ?", (name,))B501 — No certificate validation
python
# Bad
requests.get(url, verify=False)
# Good
requests.get(url) # verify=True by default
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.
# nosec - Decide team policy on LOW severity — consider skipping known false-positive-heavy tests via .
skips - Establish a baseline for legacy codebases to avoid alert fatigue during adoption.
Additional Resources
- — Complete B-code listing with severity, description, and fix pattern per plugin
references/plugin-reference.md - — Pre-commit hooks, GitHub Actions, and baseline automation workflows
references/ci-cd-integration.md