Bandit
Bandit is an open-source security-oriented static analyser for Python code, designed to find common security issues early in the development lifecycle. It processes each file, builds an Abstract Syntax Tree (AST) from it, and runs a set of security-focused plugins against the AST nodes, generating reports with severity and confidence levels. Maintained by the PyCQA community, Bandit is currently at version 1.9.4 and requires Python >=3.10. Its release cadence focuses on compatibility updates and rule maintenance, indicating a stable and actively supported utility.
Warnings
- breaking Using `subprocess` calls with `shell=True` (e.g., `subprocess.call(command, shell=True)`) is a major security vulnerability (B602) if the `command` string is derived from untrusted input, as it enables shell injection attacks.
- gotcha The Python `assert` statement (B101) should not be used for security-critical checks or enforcing interface constraints in production code. Asserts are removed when Python is run with optimizations (`python -O`), which can bypass security controls.
- gotcha Bandit can produce false positives, requiring manual review of reported issues. The tool's output provides severity and confidence levels to help prioritize findings, but human judgment is still necessary.
- gotcha Running Bandit recursively on large codebases can be time-consuming and impact development workflow if integrated as a blocking pre-commit hook for every change.
- gotcha When using configuration files (`.bandit`, `bandit.yaml`, `pyproject.toml`), only `.bandit` (INI format) is automatically discovered when running `bandit -r`. For YAML or TOML files, you must explicitly specify them using the `-c` flag.
Install
-
pip install bandit -
pip install bandit[toml] -
pip install bandit[baseline]
Quickstart
# Save this as vulnerable_app.py
import os
import subprocess
def execute_command(command_str):
# B602: subprocess_popen_with_shell_equals_true - High severity, high confidence
subprocess.call(command_str, shell=True)
def process_user_input(user_input):
# B307: eval - High severity, high confidence
eval(user_input)
if __name__ == "__main__":
print("Creating a dummy vulnerable file for Bandit scan.")
with open("dummy_code.py", "w") as f:
f.write("import subprocess\n")
f.write("command = os.environ.get('UNSAFE_COMMAND', 'ls -l')\n")
f.write("subprocess.call(command, shell=True)\n")
print("Now run Bandit from your terminal:")
print("bandit -r .\n")
print("Or specifically on the dummy file:")
print("bandit dummy_code.py\n")
print("Example output will show security issues like B602.")
# To clean up after running:
# os.remove("dummy_code.py")