Static Application Security Testing (SAST) is a key part of modern secure software development. When it comes to Python projects, Bandit shines as a powerful, open-source solution. In this guide, you’ll learn how to set up and use Bandit to spot potential security flaws before your code reaches production. What Does SAST Mean? Static Application Security Testing (SAST) is a technique used to examine source code for potential security flaws without executing the application. Unlike dynamic testing—which analyzes software during runtime—SAST focuses on reviewing the code itself to detect issues that might lead to vulnerabilities. By identifying problems during the coding phase, SAST helps prevent security incidents early on. Fixing these issues during development is more efficient and cost-effective than doing so after release. Additionally, SAST tools can be seamlessly integrated into CI/CD workflows, allowing developers to automate security scanning and maintain consistent protection throughout the development lifecycle. What is Bandit? Bandit is an open-source SAST tool designed specifically for Python code. Developed by PyCQA (Python Code Quality Authority), it scans Python code for common security issues by analyzing the abstract syntax tree (AST) of your code. Bandit can detect various security vulnerabilities, including: SQL injection vulnerabilities Usage of insecure functions or modules Hardcoded passwords and credentials Command injection vulnerabilities Cross-site scripting (XSS) vulnerabilities Insecure use of cryptographic functions In the process of finding vulnerabilities, Bandit processes each file, builds an AST(Abstract Syntax Tree) from it, and runs appropriate plugins against the AST nodes. These plugins are predefined tests and new ones can be created to extend the functionality offered by Bandit today. The tool then provides a report detailing any issues it finds, categorized by severity and confidence level, allowing developers to prioritize and address the most critical vulnerabilities. Getting Started with Bandit Let’s go through the steps to start using Bandit in your project. How to Install Bandit? Bandit is very easy to install. The best way to install it is with pip. #Create a virtual environment (optional): virtualenv bandit-env python3 -m venv bandit-env source bandit-env/bin/activate ############ #Install bandit via pip pip install bandit #If you want to include TOML support, install it with the toml extras: pip install bandit[toml] #If you want to use the bandit-baseline CLI, install it with the baseline extras: pip install bandit[baseline] #If you want to include SARIF output formatter support, install it with the sarif extras: pip install bandit[sarif] Bandit can also be installed from source. To do so, either clone the repository or download the source tarball from PyPI, then install it with: python setup.py install Alternatively, you can let pip do the downloading for you, like this: pip install git+https://github.com/PyCQA/bandit#egg=bandit Basic Usage After installation, you can run Bandit on a single file: bashbandit example.py Or scan an entire directory: bashbandit -r ./my_python_project/ Understanding Bandit Output When you run Bandit, it produces a report showing security issues found in your code. The output includes: Severity level (LOW, MEDIUM, HIGH) Confidence level (LOW, MEDIUM, HIGH) File location and line number Issue description and recommendation Here's an example of Bandit output: [B105:hardcoded_password_string] [MEDIUM] Possible hardcoded password: 'super_secret' Location: ./example.py:10 Common Security Issues Detected by Bandit Let's look at some common issues Bandit can identify and how to fix them: 1. SQL Injection SQL injection vulnerabilities occur when untrusted input is used directly in SQL queries. Vulnerable code: def get_user(user_id): query = "SELECT * FROM users WHERE id = " + user_id cursor.execute(query) Fixed code: def get_user(user_id): query = "SELECT * FROM users WHERE id = %s" cursor.execute(query, (user_id,)) 2. Hardcoded Credentials Vulnerable code: def connect_to_database(): password = "super_secret_password" db.connect("localhost", "admin", password) Fixed code: import os def connect_to_database(): password = os.environ.get("DB_PASSWORD") db.connect("localhost", "admin", password) 3. Command Injection Vulnerable code: import os def run_command(user_input): os.system("ls " + user_input) Fixed code: import subprocess def run_command(user_input): subprocess.run(["ls", user_input], check=True) Integrating Bandit into Your Development Workflow To get the most out of Bandit, incorporate it into your development workflow: Pre-commit Hook You can use pre-commit hooks to run Bandit before each commit: #.pre-commit-config.yaml repos:

Static Application Security Testing (SAST) is a key part of modern secure software development. When it comes to Python projects, Bandit shines as a powerful, open-source solution. In this guide, you’ll learn how to set up and use Bandit to spot potential security flaws before your code reaches production.
What Does SAST Mean?
Static Application Security Testing (SAST) is a technique used to examine source code for potential security flaws without executing the application. Unlike dynamic testing—which analyzes software during runtime—SAST focuses on reviewing the code itself to detect issues that might lead to vulnerabilities.
By identifying problems during the coding phase, SAST helps prevent security incidents early on. Fixing these issues during development is more efficient and cost-effective than doing so after release.
Additionally, SAST tools can be seamlessly integrated into CI/CD workflows, allowing developers to automate security scanning and maintain consistent protection throughout the development lifecycle.
What is Bandit?
Bandit is an open-source SAST tool designed specifically for Python code. Developed by PyCQA (Python Code Quality Authority), it scans Python code for common security issues by analyzing the abstract syntax tree (AST) of your code. Bandit can detect various security vulnerabilities, including:
- SQL injection vulnerabilities
- Usage of insecure functions or modules
- Hardcoded passwords and credentials
- Command injection vulnerabilities
- Cross-site scripting (XSS) vulnerabilities
- Insecure use of cryptographic functions
In the process of finding vulnerabilities, Bandit processes each file, builds an AST(Abstract Syntax Tree) from it, and runs appropriate plugins against the AST nodes. These plugins are predefined tests and new ones can be created to extend the functionality offered by Bandit today. The tool then provides a report detailing any issues it finds, categorized by severity and confidence level, allowing developers to prioritize and address the most critical vulnerabilities.
Getting Started with Bandit
Let’s go through the steps to start using Bandit in your project.
How to Install Bandit?
Bandit is very easy to install. The best way to install it is with pip.
#Create a virtual environment (optional):
virtualenv bandit-env
python3 -m venv bandit-env
source bandit-env/bin/activate
############
#Install bandit via pip
pip install bandit
#If you want to include TOML support, install it with the toml extras:
pip install bandit[toml]
#If you want to use the bandit-baseline CLI, install it with the baseline extras:
pip install bandit[baseline]
#If you want to include SARIF output formatter support, install it with the sarif extras:
pip install bandit[sarif]
Bandit can also be installed from source. To do so, either clone the repository or download the source tarball from PyPI, then install it with:
python setup.py install
Alternatively, you can let pip do the downloading for you, like this:
pip install git+https://github.com/PyCQA/bandit#egg=bandit
Basic Usage
After installation, you can run Bandit on a single file:
bashbandit example.py
Or scan an entire directory:
bashbandit -r ./my_python_project/
Understanding Bandit Output
When you run Bandit, it produces a report showing security issues found in your code. The output includes:
- Severity level (LOW, MEDIUM, HIGH)
- Confidence level (LOW, MEDIUM, HIGH)
- File location and line number
- Issue description and recommendation
Here's an example of Bandit output:
[B105:hardcoded_password_string] [MEDIUM] Possible hardcoded password: 'super_secret'
Location: ./example.py:10
Common Security Issues Detected by Bandit
Let's look at some common issues Bandit can identify and how to fix them:
1. SQL Injection
SQL injection vulnerabilities occur when untrusted input is used directly in SQL queries.
Vulnerable code:
def get_user(user_id):
query = "SELECT * FROM users WHERE id = " + user_id
cursor.execute(query)
Fixed code:
def get_user(user_id):
query = "SELECT * FROM users WHERE id = %s"
cursor.execute(query, (user_id,))
2. Hardcoded Credentials
Vulnerable code:
def connect_to_database():
password = "super_secret_password"
db.connect("localhost", "admin", password)
Fixed code:
import os
def connect_to_database():
password = os.environ.get("DB_PASSWORD")
db.connect("localhost", "admin", password)
3. Command Injection
Vulnerable code:
import os
def run_command(user_input):
os.system("ls " + user_input)
Fixed code:
import subprocess
def run_command(user_input):
subprocess.run(["ls", user_input], check=True)
Integrating Bandit into Your Development Workflow
To get the most out of Bandit, incorporate it into your development workflow:
Pre-commit Hook
You can use pre-commit hooks to run Bandit before each commit:
#.pre-commit-config.yaml
repos:
- repo: https://github.com/PyCQA/bandit
rev: 1.7.5
hooks:
- id: bandit
args: ['-ll', '-ii']
CI/CD Integration
Integrate Bandit into your CI/CD pipeline to catch security issues automatically:
# GitHub Actions example
name: Python Security Checks
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install bandit
- name: Run Bandit
run: bandit -r ./ -f json -o bandit-results.json
- name: Upload results
uses: actions/upload-artifact@v3
with:
name: bandit-results
path: bandit-results.json
Advanced Bandit Configuration
For more control over Bandit's behavior, you can create a configuration file:
# .bandit
exclude_dirs: ['tests', 'venv']
skips: ['B101', 'B311']
any_other_function_with_shell_equals_true:
no_shell: ['subprocess.Popen']
hardcoded_password_string:
hardcoded_password_string_re: '(?i)(password|passwd|pwd)'
Real-World Example: Securing a Flask Application
Let's apply Bandit to a simple Flask application to demonstrate its effectiveness:
Github Repository
Conclusion
Implementing Bandit as a SAST tool in your Python applications is a crucial step toward building more secure software. By catching security vulnerabilities early in the development process, you can prevent potential attacks and data breaches. Remember that while Bandit is a powerful tool, it should be just one part of your overall security strategy, which should also include other practices like code reviews, penetration testing, and developer security education.
Start integrating Bandit into your Python projects today to enhance your application security posture and protect your users' data from potential threats.