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.
1. Bandit — Python Code Security Linter
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.
Installation and Basic Usage
pip install bandit
bandit -r my_project/
What Bandit Catches
Bandit checks for over 200 potential security issues, including:
-
Hardcoded passwords and secrets:
B105andB106rules catch hardcoded passwords and passwords in function defaults - SQL injection: Detects string formatting in SQL queries
-
Insecure YAML loading: Flags
yaml.load()without a safe loader -
Shell injection: Catches unsafe use of
subprocessandos.system -
Insecure temp files: Detects use of
tempfile.mktempinstead ofmkstemp
Configuration
Create a bandit.yml configuration file for project-specific rules:
skips: ['B101', 'B601']
exclude_dirs:
- tests/
- migrations/
Integration with CI/CD
# 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
2. Safety — Dependency Vulnerability Scanner
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
Key Features
- Scans against PyUp's vulnerability database with over 300,000 entries
- Supports
requirements.txt,Pipfile,Pipfile.lock, andsetup.py - Can be integrated into CI/CD pipelines
- Provides detailed CVE information and remediation advice
Automated Scanning
# 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
3. Cryptography — Secure Cryptographic Primitives
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")
Best Practices
- Always use
Fernetfor symmetric encryption (it handles IVs and authentication) - Use PBKDF2 with at least 480,000 iterations for password hashing
- Never roll your own crypto — use the library's high-level APIs
- Store salts alongside hashes but never reuse them
4. Semgrep — Pattern-Based Security Analysis
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 .
Why Semgrep Over Traditional Linters
Semgrep can detect:
- Tainted data flow: Track user input from HTTP endpoints to database queries
- Authentication bypass: Detect missing auth checks on protected endpoints
-
Insecure deserialization: Flag
pickle.loads()on untrusted data - Path traversal: Catch unsanitized file path operations
# 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]
5. Trivy — Container and Filesystem Scanner
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
Docker Integration
# 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
For the complete guide with all code examples and advanced patterns, read the full article on our blog.
Originally published at WD Tech Blog. Follow for more Python tutorials, AI tools, and developer resources.
Top comments (0)