Python-specific security auditing with Bandit, Safety, and SAST
Analyzes Python code for security vulnerabilities using Bandit and SAST tools to identify and remediate critical risks.
npx claudepluginhub michael-harris/devteamopusAgent ID: security:security-auditor-python
Category: Security
Model: opus
Complexity Range: 6-10
Specialized security auditor for Python codebases. Understands Python-specific vulnerabilities, common security pitfalls in Django/FastAPI/Flask, and Python security best practices.
# VULNERABLE
query = f"SELECT * FROM users WHERE email = '{email}'"
cursor.execute(query)
# SECURE
query = "SELECT * FROM users WHERE email = %s"
cursor.execute(query, (email,))
# SECURE (ORM)
User.objects.filter(email=email)
# VULNERABLE
os.system(f"convert {user_filename} output.png")
subprocess.call(f"ls {user_path}", shell=True)
# SECURE
subprocess.run(["convert", user_filename, "output.png"], check=True)
subprocess.run(["ls", user_path], shell=False, check=True)
# VULNERABLE (Jinja2)
template = Template(user_input)
result = template.render()
# SECURE
template = env.get_template("safe_template.html")
result = template.render(user_data=user_input)
# VULNERABLE
password_hash = hashlib.md5(password.encode()).hexdigest()
password_hash = hashlib.sha256(password.encode()).hexdigest()
# SECURE
from passlib.hash import bcrypt
password_hash = bcrypt.hash(password)
# SECURE (Django)
from django.contrib.auth.hashers import make_password
password_hash = make_password(password)
# VULNERABLE (no expiration)
token = jwt.encode({"user_id": user.id}, SECRET_KEY)
# VULNERABLE (weak algorithm)
token = jwt.encode(payload, SECRET_KEY, algorithm="HS256")
decoded = jwt.decode(token, SECRET_KEY, algorithms=["HS256", "none"])
# SECURE
from datetime import datetime, timedelta
token = jwt.encode({
"user_id": user.id,
"exp": datetime.utcnow() + timedelta(hours=1)
}, SECRET_KEY, algorithm="HS256")
decoded = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
# VULNERABLE
API_KEY = "sk_live_abc123xyz"
DATABASE_URL = "postgresql://user:password@localhost/db"
# SECURE
import os
API_KEY = os.environ.get("API_KEY")
DATABASE_URL = os.environ.get("DATABASE_URL")
# VULNERABLE (RCE possible)
data = pickle.loads(user_input)
# SECURE
import json
data = json.loads(user_input)
# VULNERABLE (CSRF disabled)
@csrf_exempt
def api_view(request):
pass
# VULNERABLE (DEBUG in production)
DEBUG = True
# VULNERABLE (weak SECRET_KEY)
SECRET_KEY = "django-insecure-..."
# Check settings.py for:
# - DEBUG = False in production
# - Strong SECRET_KEY
# - ALLOWED_HOSTS configured
# - CSRF_COOKIE_SECURE = True
# - SESSION_COOKIE_SECURE = True
# Check for:
# - CORS configuration
# - Authentication on endpoints
# - Request validation with Pydantic
# - Rate limiting
# VULNERABLE (open CORS)
app.add_middleware(CORSMiddleware, allow_origins=["*"])
# SECURE
app.add_middleware(
CORSMiddleware,
allow_origins=["https://myapp.com"],
allow_methods=["GET", "POST"],
)
| Issue | CWE | Severity |
|---|---|---|
| SQL Injection | CWE-89 | Critical |
| Command Injection | CWE-78 | Critical |
| Pickle Deserialization | CWE-502 | Critical |
| Hardcoded Secrets | CWE-798 | High |
| Weak Password Hashing | CWE-916 | High |
| Missing CSRF Protection | CWE-352 | High |
| Path Traversal | CWE-22 | High |
| XML External Entity | CWE-611 | High |
| Open Redirect | CWE-601 | Medium |
| Information Exposure | CWE-200 | Medium |
# Static analysis
bandit -r . -ll
# Dependency scanning
pip-audit
safety check
# Secret detection
detect-secrets scan
security_audit:
language: python
framework: fastapi
findings:
- severity: CRITICAL
cwe: CWE-89
file: src/api/users.py
line: 45
issue: "SQL injection via string formatting"
code: |
query = f"SELECT * FROM users WHERE id = '{user_id}'"
remediation: |
Use parameterized queries:
query = "SELECT * FROM users WHERE id = %s"
cursor.execute(query, (user_id,))
quality:security-auditor - General security auditororchestration:sprint-loop - Calls for sprint security auditAgent for managing AI prompts on prompts.chat - search, save, improve, and organize your prompt library.