src/maverick/skills/maverick_python_security/SKILL.md
Python security patterns and OWASP vulnerability detection
npx skillsauth add get2knowio/maverick maverick-python-securityInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Expert guidance for identifying and preventing security vulnerabilities in Python code.
Vulnerability:
# CRITICAL VULNERABILITY
user_id = request.GET['id']
query = f"SELECT * FROM users WHERE id = {user_id}"
cursor.execute(query)
Safe Alternative:
# SAFE - parameterized query
user_id = request.GET.get('id')
if not user_id:
return HttpResponse(status=400)
query = "SELECT * FROM users WHERE id = %s"
cursor.execute(query, (user_id,))
ORM Usage (Safest):
# Django ORM - safe by default
user = User.objects.get(id=user_id)
# SQLAlchemy - safe by default
user = session.query(User).filter(User.id == user_id).first()
Red Flags:
f"...", "...".format(), %)Vulnerability:
# CRITICAL VULNERABILITY
filename = request.GET['file']
os.system(f"cat {filename}") # Command injection!
# CRITICAL VULNERABILITY
subprocess.run(f"git clone {url}", shell=True) # Shell injection!
Safe Alternative:
# SAFE - no shell, list arguments
filename = request.GET.get('file')
if not is_safe_path(filename):
raise ValueError("Invalid filename")
subprocess.run(["cat", filename], shell=False, check=True)
# SAFE - validated input, no shell
subprocess.run(["git", "clone", url], shell=False, check=True)
Rules:
shell=True with user inputos.system() with user inputsubprocess.run()Vulnerability:
# CRITICAL VULNERABILITY
filename = request.GET['file']
with open(f"/data/{filename}") as f: # Can access ../../etc/passwd
return f.read()
Safe Alternative:
from pathlib import Path
def safe_read(base_dir: Path, filename: str) -> str:
"""Safely read file, preventing path traversal."""
# Resolve to absolute path
filepath = (base_dir / filename).resolve()
# Check it's within base_dir
if not filepath.is_relative_to(base_dir):
raise ValueError("Path traversal attempt detected")
# Additional checks
if not filepath.exists():
raise FileNotFoundError()
if not filepath.is_file():
raise ValueError("Not a file")
return filepath.read_text()
Validation Pattern:
import re
def is_safe_filename(filename: str) -> bool:
"""Validate filename against path traversal."""
# Reject path separators and special characters
if re.search(r'[/\\]|\.\.', filename):
return False
# Whitelist allowed characters
if not re.match(r'^[a-zA-Z0-9_.-]+$', filename):
return False
return True
Vulnerability:
# CRITICAL - hardcoded secrets
API_KEY = "sk-1234567890abcdef"
DATABASE_PASSWORD = "MyP@ssw0rd123"
AWS_SECRET = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
Safe Alternative:
import os
from pathlib import Path
# Environment variables
API_KEY = os.environ["API_KEY"]
DATABASE_PASSWORD = os.environ["DATABASE_PASSWORD"]
# Or use python-dotenv
from dotenv import load_dotenv
load_dotenv()
API_KEY = os.getenv("API_KEY")
# Or use secrets management service (best)
from aws_secretsmanager import get_secret
API_KEY = get_secret("api-key")
.gitignore Must Include:
.env
.env.*
secrets.yaml
credentials.json
*.pem
*.key
Detection Patterns:
password=, api_key=, token=, secret= with string valuesAKIA)BEGIN PRIVATE KEY)Vulnerability:
# CRITICAL - pickle can execute arbitrary code
import pickle
data = pickle.loads(user_input) # DANGEROUS!
# CRITICAL - eval/exec with user input
result = eval(user_input) # DANGEROUS!
Safe Alternative:
import json
# SAFE - JSON can't execute code
data = json.loads(user_input)
# If you need Python objects, validate rigorously
from pydantic import BaseModel
class SafeData(BaseModel):
name: str
age: int
# This validates and raises on invalid data
data = SafeData.model_validate_json(user_input)
Rules:
pickle.loads() on untrusted dataeval() or exec() on user input__reduce_ex__ restrictionsVulnerability:
# VULNERABLE - allows XXE attacks
import xml.etree.ElementTree as ET
tree = ET.parse(user_file) # Can read local files!
Safe Alternative:
# SAFE - defusedxml prevents XXE
from defusedxml.ElementTree import parse
tree = parse(user_file)
# Or disable DTD processing
import xml.etree.ElementTree as ET
parser = ET.XMLParser()
parser.entity = {} # Disable entities
tree = ET.parse(user_file, parser=parser)
Vulnerability (Web Frameworks):
# Flask - VULNERABLE if using raw HTML
@app.route('/user/<username>')
def show_user(username):
return f"<h1>Hello {username}</h1>" # XSS!
# Django - VULNERABLE if |safe filter used
# template.html
{{ user_input|safe }} # XSS!
Safe Alternative:
# Flask - use templates with auto-escaping
from flask import render_template_string
@app.route('/user/<username>')
def show_user(username):
return render_template_string("<h1>Hello {{ username }}</h1>", username=username)
# Django - templates auto-escape by default
# template.html
{{ user_input }} # Automatically escaped
# If you must use |safe, sanitize first
from bleach import clean
safe_input = clean(user_input, tags=['b', 'i', 'em'], strip=True)
# template: {{ safe_input|safe }}
Vulnerability:
import random
# INSECURE for security purposes
session_token = random.randint(1000, 9999) # Predictable!
api_key = ''.join(random.choices('0123456789', k=32)) # Predictable!
Safe Alternative:
import secrets
# SECURE - cryptographically random
session_token = secrets.token_urlsafe(32)
api_key = secrets.token_hex(32)
# For random integers
secure_random = secrets.randbelow(10000)
# For random choices
secure_choice = secrets.choice(['a', 'b', 'c'])
Rules:
random module for security (tokens, keys, passwords)secrets module for security-related randomnesssecrets.token_urlsafe() for tokenssecrets.token_hex() for API keysVulnerability:
import hashlib
# INSECURE - MD5/SHA1 are broken
password_hash = hashlib.md5(password.encode()).hexdigest()
signature = hashlib.sha1(data.encode()).digest()
Safe Alternative:
from argon2 import PasswordHasher
from cryptography.hazmat.primitives import hashes, hmac
# SECURE password hashing
ph = PasswordHasher()
password_hash = ph.hash(password)
# Verification
try:
ph.verify(password_hash, password)
print("Password correct")
except:
print("Password incorrect")
# SECURE HMAC
key = os.urandom(32)
h = hmac.HMAC(key, hashes.SHA256())
h.update(data)
signature = h.finalize()
Approved Algorithms:
Vulnerability:
def transfer_money(from_account, to_account, amount):
# No logging!
from_account.balance -= amount
to_account.balance += amount
Safe Alternative:
import logging
logger = logging.getLogger(__name__)
def transfer_money(from_account, to_account, amount):
logger.info(
"transfer_initiated",
from=from_account.id,
to=to_account.id,
amount=amount,
)
try:
from_account.balance -= amount
to_account.balance += amount
logger.info("transfer_completed", transaction_id=tx_id)
except Exception as e:
logger.error(
"transfer_failed",
from=from_account.id,
to=to_account.id,
error=str(e),
)
raise
eval(), exec(), or __import__() on user inputshell=True without validation, XSS vulnerabilitiesdevelopment
Rust unsafe code, FFI, and safety invariants
development
Rust testing patterns (unit, integration, property-based)
development
Rust performance optimization and zero-cost abstractions
development
Rust ownership, borrowing, and lifetimes