Bandit is a free, open-source SAST tool built specifically for Python. Maintained by the Python Code Quality Authority (PyCQA), it scans Python source code for common security issues using Abstract Syntax Tree analysis.

The project has over 7,800 GitHub stars, 151 contributors, and is used by 59,500+ repositories on GitHub. Sponsored by Mercedes-Benz, Tidelift, and Stacklok, Bandit originally grew out of the OpenStack Security Project before moving to PyCQA.
What is Bandit?
Bandit parses Python files into Abstract Syntax Trees and runs security-focused plugins against the AST nodes. It ships with 47 built-in checks organized into 7 categories: injection, cryptography, XSS, framework misconfiguration, hardcoded credentials, and more.
Unlike multi-language SAST tools, Bandit does one thing: Python security analysis. Its checks are written for Python idioms and common mistake patterns, not adapted from generic rules.
Key Features
Security check categories
Bandit organizes its 47 plugins into 7 ID ranges:
| Category | Checks |
|---|---|
| B1xx — Miscellaneous | assert_used, exec_used, hardcoded_password_string, hardcoded_tmp_directory, request_without_timeout, and 9 more |
| B2xx — Framework misconfiguration | flask_debug_true, tarfile_unsafe_members |
| B3xx — Blacklist calls | Dangerous function calls like unsafe XML parsing |
| B4xx — Blacklist imports | Imports of known-vulnerable modules |
| B5xx — Cryptography | ssl_with_bad_version, weak_cryptographic_key, yaml_load, snmp_insecure_version, and 5 more |
| B6xx — Injection | subprocess_popen_with_shell_equals_true, hardcoded_sql_expressions, django_extra_used, trojansource, and 9 more |
| B7xx — XSS | jinja2_autoescape_false, use_of_mako_templates, django_mark_safe, markupsafe_markup_xss |
torch.load() calls and B615 flags insecure Hugging Face model downloads. These were added to address supply chain attacks through serialized model files.Flexible configuration
Bandit supports three configuration file formats: YAML, TOML (pyproject.toml), and INI (.bandit). You can include or exclude specific checks, skip entire directories, and configure per-plugin options.
Per-line suppression is straightforward:
# Suppress all checks on this line
result = subprocess.call(cmd, shell=True) # nosec
# Suppress specific checks only
result = subprocess.call(cmd, shell=True) # nosec B602, B607

Multiple output formats
Bandit ships 9 formatters out of the box:
| Format | Use case |
|---|---|
| Screen | Terminal output during development |
| JSON | CI/CD integration, baseline comparisons |
| SARIF | GitHub code scanning, VS Code SARIF Viewer |
| HTML | Shareable reports for stakeholders |
| XML | Integration with legacy reporting tools |
| YAML | Machine-readable, human-friendly output |
| CSV | Spreadsheet analysis |
| Text | Plain text logs |
| Custom | Build your own formatter via plugin API |
The plugin architecture lets you write custom formatters and register them through Python entry points.
Baseline comparisons
Bandit can compare scan results against a baseline file, so you only see new findings introduced since the last scan. Run it in PR checks and developers won’t have to wade through pre-existing issues.
# Generate a baseline
bandit -r src/ -f json -o baseline.json
# Scan against the baseline — only shows new issues
bandit -r src/ -b baseline.json
Getting Started
pip install bandit[sarif] for SARIF output, pip install bandit[toml] for TOML config support, or pip install bandit[baseline] for baseline comparisons.bandit -r path/to/your/code. Add -n 3 to show 3 lines of context around each finding, or --severity-level high to filter by severity..bandit INI file or add a [tool.bandit] section to your pyproject.toml. Specify which tests to run or skip: skips = ["B101", "B601"].-f sarif -o results.sarif to upload findings to GitHub code scanning.Docker usage
Bandit publishes multi-architecture container images (amd64, arm64, armv7, armv8) signed with sigstore cosign:
# Pull the container
docker pull ghcr.io/pycqa/bandit/bandit
# Scan a local directory
docker run -v $(pwd):/src ghcr.io/pycqa/bandit/bandit -r /src
Pre-commit integration
Add Bandit to your .pre-commit-config.yaml:
repos:
- repo: https://github.com/PyCQA/bandit
rev: 1.9.3
hooks:
- id: bandit
args: ["-c", "pyproject.toml"]
additional_dependencies: ["bandit[toml]"]
When to Use Bandit
Bandit works best as a Python-specific security layer alongside broader tools. Because it only does Python, it catches idiom-specific issues that multi-language SAST tools sometimes miss.
Good use cases:
- Python projects that need a free, zero-config security linter
- Pre-commit hooks to catch security issues before code reaches CI
- Adding a Python-specific check alongside multi-language tools like Semgrep or SonarQube
- Open-source projects that need an Apache 2.0 licensed scanner
- Teams scanning Python 3.10–3.14 codebases in containers or CI/CD
Bandit is not a full replacement for commercial SAST platforms if you need multi-language support, data flow analysis, or taint tracking. It catches common security anti-patterns through AST pattern matching, which is effective for the issues it targets but won’t find complex vulnerabilities that require inter-procedural analysis.
Note: Maintained by PyCQA. Sponsored by Mercedes-Benz, Tidelift, and Stacklok. Supports Python 3.10-3.14.
Comments
Powered by Giscus — comments are stored in GitHub Discussions.