Security isn’t something you bolt on after the fact. It’s a mindset, a practice, and increasingly, a set of automated tools that catch vulnerabilities before they reach production.
Python’s ecosystem has matured significantly in recent years, and the security tooling available today is both powerful and accessible. Here are five essential Python security tools that every developer should have in their toolkit.
Bandit is a security linter specifically designed for Python code. It scans your codebase for common security issues like hardcoded passwords, SQL injection vulnerabilities, and insecure function usage.
pip install bandit
bandit -r my_project/
Bandit checks for over 200 potential security issues, including:
B105 and B106 rules catch hardcoded passwords and passwords in function defaultsyaml.load() without a safe loadersubprocess and os.systemtempfile.mktemp instead of mkstempCreate a bandit.yml configuration file for project-specific rules:
skips: ['B101', 'B601']
exclude_dirs:
- tests/
- migrations/
# GitHub Actions example
- name: Security Check
run: |
pip install bandit
bandit -r src/ -f json -o bandit-report.json
if [ $? -ne 0 ]; then
echo "::warning::Security issues found. Check bandit-report.json"
fi
Safety checks your project’s dependencies against a database of known vulnerabilities. It’s essential for catching supply chain attacks and outdated packages with known CVEs.
pip install safety
safety check --full-report
requirements.txt, Pipfile, Pipfile.lock, and setup.py# safety_check.py
import subprocess
import json
def check_dependencies():
result = subprocess.run(
["safety", "check", "--json"],
capture_output=True,
text=True
)
if result.returncode != 0:
vulnerabilities = json.loads(result.stdout)
for vuln in vulnerabilities:
print(f"[CRITICAL] {vuln['package']} {vuln['version']}")
print(f" Vulnerability: {vuln['advisory']}")
print(f" Fix: Upgrade to {vuln['fixed_version']}")
return False
return True
The cryptography library is the standard for implementing secure encryption, hashing, and signing in Python. It provides a high-level interface while being backed by OpenSSL.
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
import base64
# Symmetric encryption
key = Fernet.generate_key()
cipher = Fernet(key)
encrypted = cipher.encrypt(b"sensitive data")
decrypted = cipher.decrypt(encrypted)
# Secure password hashing
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
import os
salt = os.urandom(16)
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=480000,
)
key = kdf.derive(b"password")
Fernet for symmetric encryption (it handles IVs and authentication)Semgrep goes beyond simple linting. It uses a powerful pattern language to detect complex security vulnerabilities that require understanding code semantics.
pip install semgrep
semgrep --config=auto --security-severity=WARNING .
Semgrep can detect:
pickle.loads() on untrusted data# Semgrep rule example
# rules/no-hardcoded-secrets.yml
rules:
- id: detect-hardcoded-api-key
patterns:
- pattern-either:
- pattern: $X = "$API_KEY"
- pattern: $X = "$SECRET"
- pattern: $X = "$TOKEN"
message: "Possible hardcoded API key detected"
severity: ERROR
languages: [python]
If you’re deploying Python applications in containers (and you probably should be), Trivy is an essential tool for scanning container images and filesystems for vulnerabilities.
# Install Trivy
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
# Scan a container image
trivy image my-python-app:latest
# Scan a filesystem
trivy fs /path/to/project
# Multi-stage build with security scanning
FROM python:3.12-slim as builder
COPY requirements.txt .
RUN pip install --user -r requirements.txt
FROM python:3.12-slim
COPY --from=builder /root/.local /root/.local
COPY . .
# Scan during build
trivy image --exit-code 1 --severity CRITICAL,HIGH my-python-app:latest
The real power of these tools comes when you combine them into an automated security pipeline:
# .github/workflows/security.yml
name: Security Pipeline
on: [push, pull_request]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install tools
run: |
pip install bandit safety semgrep
- name: Bandit scan
run: bandit -r src/ -f json -o bandit-report.json
- name: Safety check
run: safety check --json > safety-report.json
- name: Semgrep scan
run: semgrep --config=auto --json -o semgrep-report.json .
- name: Trivy filesystem scan
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
severity: 'CRITICAL,HIGH'
While the tools above cover specific aspects of Python security, the ecosystem is moving toward integrated solutions. Several upcoming toolkits aim to provide end-to-end security scanning — from code analysis and dependency checking to runtime monitoring and compliance reporting.
One such project gaining attention is the Python Security Toolkit, which is being developed as an all-in-one security solution. It plans to combine static analysis, dependency scanning, secret detection, and runtime protection into a single CLI tool with a unified configuration format. While it’s still in development, it represents the direction the Python security ecosystem is heading.
Security is not a one-time task — it’s a continuous process. By incorporating these tools into your daily workflow, you can catch vulnerabilities early and build more resilient Python applications.