
Security Patterns
- 1 installs
- 404 repo stars
- Updated August 5, 2026
- aiskillstore/marketplace
security-patterns is a language-agnostic skill of OWASP-aligned secure-coding patterns for web applications.
About
security-patterns is a skill covering essential security patterns and OWASP guidelines for web applications. It includes an OWASP Top 10 quick reference, input validation and output-encoding rules, authentication and authorization examples, secrets-management rules, security headers, and quick audit grep commands. A developer uses it during security review or secure coding.
- OWASP Top 10 quick reference with prevention
- Language-agnostic input validation and output encoding
- Auth, authorization, and secrets-management checklists
Security Patterns by the numbers
- 1 all-time installs (skills.sh)
- Ranked #1,835 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
security-patterns capabilities & compatibility
- Capabilities
- security audit · secure coding review · input validation · secrets management
- Use cases
- security audit · code review
- Pricing
- Free
What security-patterns says it does
## OWASP Top 10 Quick Reference
Hash passwords with bcrypt/argon2 (cost factor 12+)
npx skills add https://github.com/aiskillstore/marketplace --skill security-patternsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 404 |
| Last updated | August 5, 2026 |
| Repository | aiskillstore/marketplace ↗ |
What it does
Apply OWASP-aligned validation, auth, and secrets patterns during security review.
Who is it for?
Security reviews and secure coding across validation, auth, authorization, and secrets
Skip if: Deep framework-specific configuration beyond the referenced examples
When should I use this skill?
Doing a security review or applying OWASP, input-validation, or secrets-management patterns
What you get
Code that follows OWASP-aligned validation, encoding, auth, and secrets patterns.
- OWASP reference table
- Auth checklist
- Security audit grep commands
By the numbers
- OWASP Top 10 reference table (A01-A10)
- 6-item auth checklist
Files
Security Patterns
Essential security patterns for web applications.
OWASP Top 10 Quick Reference
| Rank | Vulnerability | Prevention |
|---|---|---|
| A01 | Broken Access Control | Check permissions server-side, deny by default |
| A02 | Cryptographic Failures | Use TLS, hash passwords, encrypt sensitive data |
| A03 | Injection | Parameterized queries, validate input |
| A04 | Insecure Design | Threat modeling, secure defaults |
| A05 | Security Misconfiguration | Harden configs, disable unused features |
| A06 | Vulnerable Components | Update dependencies, audit regularly |
| A07 | Auth Failures | MFA, rate limiting, secure session management |
| A08 | Data Integrity Failures | Verify signatures, use trusted sources |
| A09 | Logging Failures | Log security events, protect logs |
| A10 | SSRF | Validate URLs, allowlist destinations |
Input Validation
# WRONG - Trust user input
def search(query):
return db.execute(f"SELECT * FROM users WHERE name = '{query}'")
# CORRECT - Parameterized query
def search(query):
return db.execute("SELECT * FROM users WHERE name = ?", [query])Validation Rules
Always validate:
- Type (string, int, email format)
- Length (min/max bounds)
- Range (numeric bounds)
- Format (regex for patterns)
- Allowlist (known good values)
Never trust:
- URL parameters
- Form data
- HTTP headers
- Cookies
- File uploadsOutput Encoding
// WRONG - Direct HTML insertion
element.innerHTML = userInput;
// CORRECT - Text content (auto-escapes)
element.textContent = userInput;
// CORRECT - Template with escaping
render(`<div>${escapeHtml(userInput)}</div>`);Encoding by Context
| Context | Encoding |
|---|---|
| HTML body | HTML entity encode |
| HTML attribute | Attribute encode + quote |
| JavaScript | JS encode |
| URL parameter | URL encode |
| CSS | CSS encode |
Authentication
# Password hashing (use bcrypt, argon2, or scrypt)
import bcrypt
def hash_password(password: str) -> bytes:
return bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))
def verify_password(password: str, hashed: bytes) -> bool:
return bcrypt.checkpw(password.encode(), hashed)Auth Checklist
- [ ] Hash passwords with bcrypt/argon2 (cost factor 12+)
- [ ] Implement rate limiting on login
- [ ] Use secure session tokens (random, long)
- [ ] Set secure cookie flags (HttpOnly, Secure, SameSite)
- [ ] Implement account lockout after failed attempts
- [ ] Support MFA for sensitive operations
Authorization
# WRONG - Check only authentication
@login_required
def delete_post(post_id):
post = Post.get(post_id)
post.delete()
# CORRECT - Check authorization
@login_required
def delete_post(post_id):
post = Post.get(post_id)
if post.author_id != current_user.id and not current_user.is_admin:
raise Forbidden("Not authorized to delete this post")
post.delete()Secrets Management
# WRONG - Hardcoded secrets
API_KEY = "sk-1234567890abcdef"
# CORRECT - Environment variables
API_KEY = os.environ["API_KEY"]
# BETTER - Secrets manager
API_KEY = secrets_client.get_secret("api-key")Secret Handling Rules
DO:
- Use environment variables or secrets manager
- Rotate secrets regularly
- Use different secrets per environment
- Audit secret access
DON'T:
- Commit secrets to git
- Log secrets
- Include secrets in error messages
- Share secrets in plain textSecurity Headers
Content-Security-Policy: default-src 'self'; script-src 'self'
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Strict-Transport-Security: max-age=31536000; includeSubDomains
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), camera=()Quick Security Audit
# Find hardcoded secrets
rg -i "(password|secret|api_key|token)\s*=\s*['\"][^'\"]+['\"]" --type py
# Find SQL injection risks
rg "execute\(f['\"]|format\(" --type py
# Find eval/exec usage
rg "\b(eval|exec)\s*\(" --type py
# Check for TODO security items
rg -i "TODO.*security|FIXME.*security"Additional Resources
./references/owasp-detailed.md- Full OWASP Top 10 details./references/auth-patterns.md- JWT, OAuth, session management./references/crypto-patterns.md- Encryption, hashing, signatures./references/secure-headers.md- HTTP security headers guide
Scripts
./scripts/security-scan.sh- Quick security grep patterns./scripts/dependency-audit.sh- Check for vulnerable dependencies
Authentication Patterns
Secure authentication implementation patterns.
Password Hashing
bcrypt (Recommended)
import bcrypt
def hash_password(password: str) -> bytes:
"""Hash password with bcrypt."""
salt = bcrypt.gensalt(rounds=12) # Cost factor 12
return bcrypt.hashpw(password.encode('utf-8'), salt)
def verify_password(password: str, hashed: bytes) -> bool:
"""Verify password against hash."""
return bcrypt.checkpw(password.encode('utf-8'), hashed)
# Usage
hashed = hash_password("user_password")
is_valid = verify_password("user_password", hashed)Argon2 (Modern Alternative)
from argon2 import PasswordHasher
ph = PasswordHasher(
time_cost=3, # Iterations
memory_cost=65536, # 64MB
parallelism=4, # Threads
)
def hash_password(password: str) -> str:
return ph.hash(password)
def verify_password(password: str, hashed: str) -> bool:
try:
ph.verify(hashed, password)
return True
except:
return FalseSession Management
Secure Session Configuration
from flask import Flask
from datetime import timedelta
app = Flask(__name__)
app.config.update(
SECRET_KEY=os.environ['SECRET_KEY'], # Strong random key
SESSION_COOKIE_NAME='__session',
SESSION_COOKIE_SECURE=True, # HTTPS only
SESSION_COOKIE_HTTPONLY=True, # No JavaScript access
SESSION_COOKIE_SAMESITE='Strict', # CSRF protection
PERMANENT_SESSION_LIFETIME=timedelta(hours=1),
)Session Token Generation
import secrets
def generate_session_id() -> str:
"""Generate cryptographically secure session ID."""
return secrets.token_urlsafe(32) # 256 bits of entropy
def generate_csrf_token() -> str:
"""Generate CSRF token."""
return secrets.token_hex(32)JWT Patterns
JWT Generation
import jwt
from datetime import datetime, timedelta
SECRET_KEY = os.environ['JWT_SECRET']
ALGORITHM = "HS256"
def create_token(user_id: int, expires_delta: timedelta = timedelta(hours=1)) -> str:
expire = datetime.utcnow() + expires_delta
payload = {
"sub": str(user_id),
"exp": expire,
"iat": datetime.utcnow(),
"jti": secrets.token_urlsafe(16), # Unique token ID
}
return jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM)
def verify_token(token: str) -> dict:
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
return payload
except jwt.ExpiredSignatureError:
raise AuthError("Token expired")
except jwt.InvalidTokenError:
raise AuthError("Invalid token")JWT Best Practices
# DO
- Use strong secret (256+ bits)
- Set short expiration (15min - 1hr)
- Include jti for revocation
- Use HTTPS only
- Store in httpOnly cookie (not localStorage)
# DON'T
- Store sensitive data in payload (it's base64, not encrypted)
- Use long expiration times
- Send in URL parameters
- Use weak algorithms (none, HS256 with weak key)Refresh Token Pattern
def create_tokens(user_id: int) -> tuple[str, str]:
"""Create access and refresh token pair."""
access_token = create_token(
user_id,
expires_delta=timedelta(minutes=15),
token_type="access"
)
refresh_token = create_token(
user_id,
expires_delta=timedelta(days=7),
token_type="refresh"
)
return access_token, refresh_token
def refresh_access_token(refresh_token: str) -> str:
"""Generate new access token from refresh token."""
payload = verify_token(refresh_token)
if payload.get("token_type") != "refresh":
raise AuthError("Not a refresh token")
# Check if refresh token is revoked
if is_token_revoked(payload["jti"]):
raise AuthError("Token revoked")
return create_token(payload["sub"], token_type="access")OAuth 2.0 Flow
Authorization Code Flow
from authlib.integrations.flask_client import OAuth
oauth = OAuth(app)
oauth.register(
name='google',
client_id=os.environ['GOOGLE_CLIENT_ID'],
client_secret=os.environ['GOOGLE_CLIENT_SECRET'],
access_token_url='https://oauth2.googleapis.com/token',
authorize_url='https://accounts.google.com/o/oauth2/auth',
api_base_url='https://www.googleapis.com/',
client_kwargs={'scope': 'openid email profile'},
)
@app.route('/login/google')
def google_login():
redirect_uri = url_for('google_callback', _external=True)
return oauth.google.authorize_redirect(redirect_uri)
@app.route('/callback/google')
def google_callback():
token = oauth.google.authorize_access_token()
user_info = oauth.google.get('oauth2/v3/userinfo').json()
# Find or create user
user = find_or_create_user(
email=user_info['email'],
name=user_info['name'],
oauth_provider='google',
oauth_id=user_info['sub']
)
login_user(user)
return redirect('/')Multi-Factor Authentication
TOTP Implementation
import pyotp
def generate_totp_secret() -> str:
"""Generate new TOTP secret for user."""
return pyotp.random_base32()
def get_totp_uri(secret: str, email: str) -> str:
"""Generate URI for authenticator app."""
totp = pyotp.TOTP(secret)
return totp.provisioning_uri(name=email, issuer_name="MyApp")
def verify_totp(secret: str, code: str) -> bool:
"""Verify TOTP code."""
totp = pyotp.TOTP(secret)
return totp.verify(code, valid_window=1) # Allow 30s driftBackup Codes
def generate_backup_codes(count: int = 10) -> list[str]:
"""Generate one-time backup codes."""
return [secrets.token_hex(4) for _ in range(count)]
def use_backup_code(user_id: int, code: str) -> bool:
"""Verify and consume backup code."""
user = get_user(user_id)
if code in user.backup_codes:
user.backup_codes.remove(code)
user.save()
return True
return FalseRate Limiting
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
limiter = Limiter(
app,
key_func=get_remote_address,
default_limits=["200 per day", "50 per hour"]
)
@app.route("/login", methods=["POST"])
@limiter.limit("5 per minute")
def login():
# Rate limited to 5 attempts per minute per IP
pass
@app.route("/api/sensitive")
@limiter.limit("10 per minute", key_func=lambda: current_user.id)
def sensitive_endpoint():
# Rate limited per user, not IP
passAccount Security
Account Lockout
MAX_FAILED_ATTEMPTS = 5
LOCKOUT_DURATION = timedelta(minutes=30)
def record_failed_login(user_id: int) -> None:
user = get_user(user_id)
user.failed_login_attempts += 1
user.last_failed_login = datetime.utcnow()
if user.failed_login_attempts >= MAX_FAILED_ATTEMPTS:
user.locked_until = datetime.utcnow() + LOCKOUT_DURATION
security_logger.warning(f"Account locked: {user.email}")
user.save()
def check_account_locked(user_id: int) -> bool:
user = get_user(user_id)
if user.locked_until and user.locked_until > datetime.utcnow():
return True
return False
def reset_failed_attempts(user_id: int) -> None:
user = get_user(user_id)
user.failed_login_attempts = 0
user.locked_until = None
user.save()Password Reset
def create_reset_token(user_id: int) -> str:
"""Create password reset token."""
token = secrets.token_urlsafe(32)
expires = datetime.utcnow() + timedelta(hours=1)
# Store hash of token, not token itself
token_hash = hashlib.sha256(token.encode()).hexdigest()
store_reset_token(user_id, token_hash, expires)
return token
def verify_reset_token(token: str) -> int | None:
"""Verify reset token and return user_id."""
token_hash = hashlib.sha256(token.encode()).hexdigest()
record = get_reset_token(token_hash)
if not record or record.expires < datetime.utcnow():
return None
# Invalidate token after use
delete_reset_token(token_hash)
return record.user_idCryptography Patterns
Secure cryptographic implementations.
Symmetric Encryption
AES-GCM (Recommended)
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
def encrypt(plaintext: bytes, key: bytes) -> bytes:
"""Encrypt data with AES-GCM."""
# Generate random 96-bit nonce
nonce = os.urandom(12)
aesgcm = AESGCM(key)
ciphertext = aesgcm.encrypt(nonce, plaintext, associated_data=None)
# Prepend nonce to ciphertext
return nonce + ciphertext
def decrypt(data: bytes, key: bytes) -> bytes:
"""Decrypt AES-GCM encrypted data."""
nonce = data[:12]
ciphertext = data[12:]
aesgcm = AESGCM(key)
return aesgcm.decrypt(nonce, ciphertext, associated_data=None)
# Generate a secure key
key = AESGCM.generate_key(bit_length=256)Fernet (Simple, Safe)
from cryptography.fernet import Fernet
# Generate key
key = Fernet.generate_key()
# Encrypt
f = Fernet(key)
token = f.encrypt(b"secret message")
# Decrypt
plaintext = f.decrypt(token)Key Derivation
PBKDF2
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
import os
def derive_key(password: str, salt: bytes = None) -> tuple[bytes, bytes]:
"""Derive encryption key from password."""
if salt is None:
salt = os.urandom(16)
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=600000, # OWASP 2023 recommendation
)
key = kdf.derive(password.encode())
return key, saltArgon2 for Key Derivation
from argon2.low_level import hash_secret_raw, Type
def derive_key_argon2(password: str, salt: bytes = None) -> tuple[bytes, bytes]:
"""Derive key using Argon2id."""
if salt is None:
salt = os.urandom(16)
key = hash_secret_raw(
secret=password.encode(),
salt=salt,
time_cost=3,
memory_cost=65536,
parallelism=4,
hash_len=32,
type=Type.ID,
)
return key, saltHashing
SHA-256 (Data Integrity)
import hashlib
def hash_data(data: bytes) -> str:
"""Hash data for integrity checking."""
return hashlib.sha256(data).hexdigest()
def verify_integrity(data: bytes, expected_hash: str) -> bool:
"""Verify data hasn't been modified."""
return hashlib.sha256(data).hexdigest() == expected_hashHMAC (Message Authentication)
import hmac
import hashlib
def create_signature(message: bytes, key: bytes) -> str:
"""Create HMAC signature."""
return hmac.new(key, message, hashlib.sha256).hexdigest()
def verify_signature(message: bytes, signature: str, key: bytes) -> bool:
"""Verify HMAC signature (timing-safe)."""
expected = hmac.new(key, message, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)Digital Signatures
RSA Signatures
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import serialization
# Generate key pair
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=4096,
)
public_key = private_key.public_key()
def sign(message: bytes, private_key) -> bytes:
"""Sign message with RSA."""
return private_key.sign(
message,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
def verify(message: bytes, signature: bytes, public_key) -> bool:
"""Verify RSA signature."""
try:
public_key.verify(
signature,
message,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
return True
except:
return FalseEd25519 (Modern Alternative)
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
# Generate keys
private_key = Ed25519PrivateKey.generate()
public_key = private_key.public_key()
# Sign
signature = private_key.sign(message)
# Verify
try:
public_key.verify(signature, message)
print("Valid signature")
except:
print("Invalid signature")Secure Random
import secrets
import os
# Cryptographically secure random bytes
random_bytes = os.urandom(32)
# Secure token generation
token = secrets.token_hex(32) # 64 hex chars
token = secrets.token_urlsafe(32) # URL-safe base64
token = secrets.token_bytes(32) # Raw bytes
# Secure random integer
pin = secrets.randbelow(1000000) # 0-999999
# Secure random choice
selected = secrets.choice(options)Key Storage
Environment Variables
import os
# Load key from environment
key = os.environ.get('ENCRYPTION_KEY')
if not key:
raise RuntimeError("ENCRYPTION_KEY not set")
key_bytes = bytes.fromhex(key)Key Management Service (AWS KMS)
import boto3
kms = boto3.client('kms')
def encrypt_with_kms(plaintext: bytes, key_id: str) -> bytes:
"""Encrypt using AWS KMS."""
response = kms.encrypt(
KeyId=key_id,
Plaintext=plaintext,
)
return response['CiphertextBlob']
def decrypt_with_kms(ciphertext: bytes) -> bytes:
"""Decrypt using AWS KMS."""
response = kms.decrypt(CiphertextBlob=ciphertext)
return response['Plaintext']Common Mistakes
DON'T: Use ECB Mode
# WRONG - ECB reveals patterns
cipher = Cipher(algorithms.AES(key), modes.ECB())
# CORRECT - Use GCM or CBC with HMAC
cipher = Cipher(algorithms.AES(key), modes.GCM(iv))DON'T: Reuse Nonces/IVs
# WRONG - Static IV
iv = b'1234567890123456'
# CORRECT - Random IV each time
iv = os.urandom(16)DON'T: Roll Your Own Crypto
# WRONG - Custom encryption
def encrypt(data, key):
return bytes([b ^ key[i % len(key)] for i, b in enumerate(data)])
# CORRECT - Use established libraries
from cryptography.fernet import FernetDON'T: Use MD5 or SHA1 for Security
# WRONG - Weak hash
import hashlib
hash = hashlib.md5(password.encode())
# CORRECT - Use bcrypt for passwords
import bcrypt
hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt())Quick Reference
| Purpose | Algorithm | Library |
|---|---|---|
| Password hashing | bcrypt, Argon2 | bcrypt, argon2-cffi |
| Symmetric encryption | AES-256-GCM | cryptography |
| Key derivation | PBKDF2, Argon2 | cryptography, argon2 |
| Data integrity | SHA-256 | hashlib |
| Message auth | HMAC-SHA256 | hmac |
| Digital signatures | Ed25519, RSA-PSS | cryptography |
| Random bytes | CSPRNG | secrets, os.urandom |
OWASP Top 10 Detailed Guide
In-depth coverage of OWASP Top 10 2021 vulnerabilities.
A01: Broken Access Control
Description
Access control enforces policy such that users cannot act outside their intended permissions.
Examples
- Bypassing access control by modifying URL, state, or HTML
- Viewing or editing someone else's account
- Privilege escalation (acting as user without login, or user acting as admin)
- Metadata manipulation (replay/tampering JWT, cookies, hidden fields)
- CORS misconfiguration allowing unauthorized API access
- Force browsing to authenticated pages or privileged pages
Prevention
# WRONG - Client-side check only
if user.role == "admin":
show_admin_button()
# CORRECT - Server-side enforcement
@app.route("/admin/users")
def admin_users():
if not current_user.has_role("admin"):
abort(403)
return render_template("admin/users.html")
# CORRECT - Deny by default
def get_resource(resource_id):
resource = Resource.get(resource_id)
if resource.owner_id != current_user.id:
raise Forbidden("Not your resource")
return resourceChecklist
- [ ] Deny by default except for public resources
- [ ] Implement access control once, reuse everywhere
- [ ] Record access control failures, alert on repeated attempts
- [ ] Disable web server directory listing
- [ ] Ensure file metadata not accessible
A02: Cryptographic Failures
Description
Failures related to cryptography leading to exposure of sensitive data.
Examples
- Data transmitted in clear text (HTTP, SMTP, FTP)
- Old/weak cryptographic algorithms (MD5, SHA1, DES)
- Default or weak crypto keys
- Improper certificate validation
- Passwords stored without salted hashing
Prevention
# WRONG - Weak hashing
import hashlib
password_hash = hashlib.md5(password.encode()).hexdigest()
# CORRECT - bcrypt with cost factor
import bcrypt
password_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))
# WRONG - ECB mode
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
cipher = Cipher(algorithms.AES(key), modes.ECB())
# CORRECT - GCM mode with random IV
cipher = Cipher(algorithms.AES(key), modes.GCM(iv))Checklist
- [ ] Classify data by sensitivity
- [ ] Don't store sensitive data unnecessarily
- [ ] Encrypt all sensitive data at rest
- [ ] Use TLS for all data in transit
- [ ] Use strong, standard algorithms
- [ ] Store passwords with bcrypt, scrypt, Argon2, or PBKDF2
A03: Injection
Description
Hostile data sent to an interpreter as part of a command or query.
Examples
- SQL Injection
- NoSQL Injection
- OS Command Injection
- LDAP Injection
- XPath Injection
- Template Injection
Prevention
# WRONG - SQL Injection
query = f"SELECT * FROM users WHERE name = '{name}'"
# CORRECT - Parameterized query
cursor.execute("SELECT * FROM users WHERE name = ?", [name])
# WRONG - Command Injection
os.system(f"ping {host}")
# CORRECT - Use subprocess with list
subprocess.run(["ping", "-c", "4", host], capture_output=True)
# WRONG - Template Injection
template = Template(user_input)
# CORRECT - Safe templating
template = env.get_template("page.html")
template.render(user_data=user_input)Detection Patterns
# Find SQL injection risks
rg "execute\(f['\"]|format\(|\.format\(" --type py
# Find command injection
rg "os\.system\(|subprocess\.(run|call|Popen)\([^,\[]*\+" --type pyA04: Insecure Design
Description
Missing or ineffective security controls from design phase.
Prevention
- Use threat modeling during design
- Integrate security requirements in user stories
- Use secure design patterns
- Write unit and integration tests for security controls
- Segregate tenants robustly
A05: Security Misconfiguration
Description
Missing or improper security hardening across the application stack.
Examples
- Default accounts enabled
- Unnecessary features enabled
- Error messages revealing stack traces
- Missing security headers
- Out of date software
Prevention
# Secure headers middleware
security_headers:
Content-Security-Policy: "default-src 'self'"
X-Frame-Options: "DENY"
X-Content-Type-Options: "nosniff"
Strict-Transport-Security: "max-age=31536000"
# Disable debug in production
DEBUG: false
ALLOWED_HOSTS: ["example.com"]A06: Vulnerable and Outdated Components
Description
Using components with known vulnerabilities.
Prevention
# Python - pip audit
pip install pip-audit
pip-audit
# JavaScript - npm audit
npm audit
npm audit fix
# General - Snyk
snyk test
snyk monitor
# GitHub Dependabot
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"A07: Identification and Authentication Failures
Description
Confirmation of user's identity and session management weaknesses.
Examples
- Permits brute force attacks
- Permits weak passwords
- Weak credential recovery
- Plain text or weakly hashed passwords
- Missing MFA
- Session IDs in URL
Prevention
# Rate limiting
from flask_limiter import Limiter
limiter = Limiter(app, key_func=get_remote_address)
@app.route("/login", methods=["POST"])
@limiter.limit("5 per minute")
def login():
# Login logic
# Secure session configuration
app.config.update(
SESSION_COOKIE_SECURE=True,
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SAMESITE='Strict',
PERMANENT_SESSION_LIFETIME=timedelta(hours=1)
)A08: Software and Data Integrity Failures
Description
Code and infrastructure without integrity verification.
Examples
- Insecure CI/CD pipeline
- Auto-update without verification
- Untrusted deserialization
Prevention
# WRONG - Pickle from untrusted source
import pickle
data = pickle.loads(user_input) # RCE vulnerability!
# CORRECT - Use JSON for untrusted data
import json
data = json.loads(user_input)
# Verify signatures
import hmac
def verify_webhook(payload, signature, secret):
expected = hmac.new(secret, payload, 'sha256').hexdigest()
return hmac.compare_digest(expected, signature)A09: Security Logging and Monitoring Failures
Description
Without logging and monitoring, breaches cannot be detected.
What to Log
- Login successes and failures
- Access control failures
- Input validation failures
- High-value transactions
Prevention
import logging
security_logger = logging.getLogger("security")
def login(username, password):
user = authenticate(username, password)
if user:
security_logger.info(f"Login success: {username}")
return user
else:
security_logger.warning(f"Login failed: {username}")
raise AuthenticationError()
# Alert on suspicious patterns
if failed_logins_count > 10:
security_logger.critical(f"Brute force detected: {ip_address}")
alert_security_team(ip_address)A10: Server-Side Request Forgery (SSRF)
Description
Application fetches remote resource without validating user-supplied URL.
Examples
- Accessing internal services
- Reading cloud metadata
- Port scanning internal network
Prevention
# WRONG - Direct URL fetch
import requests
def fetch(url):
return requests.get(url) # Can fetch internal URLs!
# CORRECT - Validate URL
from urllib.parse import urlparse
ALLOWED_HOSTS = {"api.example.com", "cdn.example.com"}
def fetch(url):
parsed = urlparse(url)
if parsed.hostname not in ALLOWED_HOSTS:
raise ValueError("Host not allowed")
if parsed.scheme not in ("http", "https"):
raise ValueError("Scheme not allowed")
return requests.get(url)HTTP Security Headers
Essential security headers for web applications.
Complete Header Set
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()
X-XSS-Protection: 0Content-Security-Policy (CSP)
Basic CSP
Content-Security-Policy: default-src 'self'Detailed CSP Directives
| Directive | Purpose | Example |
|---|---|---|
default-src | Fallback for other directives | 'self' |
script-src | JavaScript sources | 'self' https://cdn.example.com |
style-src | CSS sources | 'self' 'unsafe-inline' |
img-src | Image sources | 'self' data: https: |
font-src | Font sources | 'self' https://fonts.gstatic.com |
connect-src | AJAX, WebSocket, fetch | 'self' https://api.example.com |
frame-src | iframe sources | 'none' |
frame-ancestors | Who can embed this page | 'none' |
base-uri | Restrict base element | 'self' |
form-action | Form submission targets | 'self' |
upgrade-insecure-requests | Upgrade HTTP to HTTPS | (no value) |
CSP Values
'self' - Same origin
'none' - Block all
'unsafe-inline' - Allow inline (avoid!)
'unsafe-eval' - Allow eval() (avoid!)
'strict-dynamic' - Trust scripts loaded by trusted scripts
'nonce-abc123' - Allow specific inline with nonce
'sha256-...' - Allow specific inline by hash
https: - Any HTTPS URL
data: - Data URLsCSP for Common Frameworks
React/Vue/Angular (Production)
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self' https://api.yourapp.comWith CDN
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.netReport-Only Mode
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-reportStrict-Transport-Security (HSTS)
Strict-Transport-Security: max-age=31536000; includeSubDomains; preloadmax-age=31536000- Browser remembers for 1 yearincludeSubDomains- Apply to all subdomainspreload- Submit to browser preload lists
Implementation
# Flask
@app.after_request
def add_hsts(response):
response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
return response
# Express
app.use(helmet.hsts({
maxAge: 31536000,
includeSubDomains: true,
preload: true
}))X-Frame-Options
X-Frame-Options: DENYDENY- Never allow framingSAMEORIGIN- Only same origin can frameALLOW-FROM uri- Specific origin (deprecated, use CSP)
X-Content-Type-Options
X-Content-Type-Options: nosniffPrevents MIME type sniffing. Always use this.
Referrer-Policy
Referrer-Policy: strict-origin-when-cross-origin| Value | Behavior |
|---|---|
no-referrer | Never send referrer |
same-origin | Only to same origin |
strict-origin | Send origin only, not path |
strict-origin-when-cross-origin | Full URL same-origin, origin cross-origin |
Permissions-Policy
Permissions-Policy: accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()Disable browser features you don't use:
Permissions-Policy:
camera=(), # Disable camera
microphone=(), # Disable microphone
geolocation=(self), # Only this origin
payment=* # Allow allImplementation Examples
Python Flask
from flask import Flask
app = Flask(__name__)
@app.after_request
def add_security_headers(response):
response.headers['Content-Security-Policy'] = "default-src 'self'"
response.headers['X-Content-Type-Options'] = 'nosniff'
response.headers['X-Frame-Options'] = 'DENY'
response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
response.headers['Referrer-Policy'] = 'strict-origin-when-cross-origin'
return responsePython FastAPI
from fastapi import FastAPI
from starlette.middleware import Middleware
from starlette.middleware.httpsredirect import HTTPSRedirectMiddleware
app = FastAPI()
@app.middleware("http")
async def add_security_headers(request, call_next):
response = await call_next(request)
response.headers["Content-Security-Policy"] = "default-src 'self'"
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
return responseNode.js Express (Helmet)
const helmet = require('helmet');
app.use(helmet());
// Or with custom config
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "cdn.example.com"],
}
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
}
}));Nginx
add_header Content-Security-Policy "default-src 'self'" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;Testing Headers
# Check headers with curl
curl -I https://example.com
# Security header scanner
# https://securityheaders.com
# Mozilla Observatory
# https://observatory.mozilla.orgQuick Checklist
- [ ] CSP with restrictive default-src
- [ ] HSTS with 1 year max-age
- [ ] X-Frame-Options: DENY
- [ ] X-Content-Type-Options: nosniff
- [ ] Referrer-Policy set
- [ ] Permissions-Policy restricting unused features
- [ ] No X-Powered-By header (remove it)
- [ ] Test with securityheaders.com
#!/bin/bash
# Audit dependencies for known vulnerabilities
# Usage: ./dependency-audit.sh
set -e
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
echo "=== Dependency Security Audit ==="
echo ""
# Python
if [ -f "requirements.txt" ] || [ -f "pyproject.toml" ]; then
echo "--- Python Dependencies ---"
if command -v pip-audit &> /dev/null; then
echo "Running pip-audit..."
pip-audit || true
elif command -v safety &> /dev/null; then
echo "Running safety check..."
safety check || true
else
echo -e "${YELLOW}Install pip-audit or safety for Python vulnerability scanning${NC}"
echo " pip install pip-audit"
fi
echo ""
fi
# Node.js
if [ -f "package.json" ]; then
echo "--- Node.js Dependencies ---"
if command -v npm &> /dev/null; then
echo "Running npm audit..."
npm audit --audit-level=moderate || true
fi
echo ""
fi
# Go
if [ -f "go.mod" ]; then
echo "--- Go Dependencies ---"
if command -v govulncheck &> /dev/null; then
echo "Running govulncheck..."
govulncheck ./... || true
else
echo -e "${YELLOW}Install govulncheck for Go vulnerability scanning${NC}"
echo " go install golang.org/x/vuln/cmd/govulncheck@latest"
fi
echo ""
fi
# Rust
if [ -f "Cargo.toml" ]; then
echo "--- Rust Dependencies ---"
if command -v cargo-audit &> /dev/null; then
echo "Running cargo audit..."
cargo audit || true
else
echo -e "${YELLOW}Install cargo-audit for Rust vulnerability scanning${NC}"
echo " cargo install cargo-audit"
fi
echo ""
fi
# Docker
if [ -f "Dockerfile" ]; then
echo "--- Docker Image ---"
if command -v trivy &> /dev/null; then
echo "Running trivy on Dockerfile..."
trivy config Dockerfile || true
else
echo -e "${YELLOW}Install trivy for container vulnerability scanning${NC}"
echo " brew install trivy"
fi
echo ""
fi
echo "=== Audit Complete ==="
echo ""
echo "Recommended actions:"
echo "1. Update vulnerable packages to patched versions"
echo "2. Review advisories for workarounds if updates unavailable"
echo "3. Consider alternative packages for unmaintained dependencies"
#!/bin/bash
# Quick security scan using grep patterns
# Usage: ./security-scan.sh [directory]
set -e
DIR="${1:-.}"
RED='\033[0;31m'
YELLOW='\033[1;33m'
GREEN='\033[0;32m'
NC='\033[0m'
echo "=== Security Scan: $DIR ==="
echo ""
ISSUES=0
check_pattern() {
local name="$1"
local pattern="$2"
local type="$3"
echo -n "Checking: $name... "
if rg -l "$pattern" "$DIR" --type "$type" 2>/dev/null | head -5 | grep -q .; then
echo -e "${RED}FOUND${NC}"
rg -n "$pattern" "$DIR" --type "$type" 2>/dev/null | head -10
echo ""
ISSUES=$((ISSUES + 1))
else
echo -e "${GREEN}OK${NC}"
fi
}
# Python checks
echo "--- Python Security Checks ---"
check_pattern "Hardcoded secrets" "(password|secret|api_key|token)\s*=\s*['\"][^'\"]{8,}['\"]" "py"
check_pattern "SQL injection (f-strings)" "execute\(f['\"]" "py"
check_pattern "SQL injection (format)" "execute\(.*\.format\(" "py"
check_pattern "eval() usage" "\beval\s*\(" "py"
check_pattern "exec() usage" "\bexec\s*\(" "py"
check_pattern "pickle.loads" "pickle\.loads?\(" "py"
check_pattern "os.system" "os\.system\(" "py"
check_pattern "shell=True" "subprocess.*shell\s*=\s*True" "py"
check_pattern "MD5 hashing" "hashlib\.md5\(" "py"
check_pattern "SHA1 hashing" "hashlib\.sha1\(" "py"
echo ""
# JavaScript checks
echo "--- JavaScript Security Checks ---"
check_pattern "innerHTML" "\.innerHTML\s*=" "js"
check_pattern "eval() usage" "\beval\s*\(" "js"
check_pattern "document.write" "document\.write\(" "js"
echo ""
# General checks
echo "--- General Security Checks ---"
echo -n "Checking: .env files in git... "
if git ls-files | grep -E "\.env$|\.env\." | grep -q .; then
echo -e "${RED}FOUND${NC}"
git ls-files | grep -E "\.env$|\.env\."
ISSUES=$((ISSUES + 1))
else
echo -e "${GREEN}OK${NC}"
fi
echo -n "Checking: TODO/FIXME security items... "
if rg -i "TODO.*security|FIXME.*security|HACK.*security" "$DIR" 2>/dev/null | head -5 | grep -q .; then
echo -e "${YELLOW}FOUND${NC}"
rg -i "TODO.*security|FIXME.*security|HACK.*security" "$DIR" 2>/dev/null | head -10
ISSUES=$((ISSUES + 1))
else
echo -e "${GREEN}OK${NC}"
fi
echo ""
echo "=== Summary ==="
if [ $ISSUES -eq 0 ]; then
echo -e "${GREEN}No issues found!${NC}"
exit 0
else
echo -e "${RED}Found $ISSUES potential security issues${NC}"
echo "Review the findings above and address any real vulnerabilities."
exit 1
fi
{
"schema_version": "2.0",
"meta": {
"generated_at": "2026-01-16T14:17:53.759Z",
"slug": "0xdarkmatter-security-patterns",
"source_url": "https://github.com/0xDarkMatter/claude-mods/tree/main/skills/security-patterns",
"source_ref": "main",
"model": "claude",
"analysis_version": "3.0.0",
"source_type": "community",
"content_hash": "b71786fd0663c74d4d527d1a939a140b58a46cb4ce5ae79f394d2c6c52405224",
"tree_hash": "0533bc3fcfb3a8e369ad5f83fec76cd66e7370388aa58f291ba9a14256db6a28"
},
"skill": {
"name": "security-patterns",
"description": "Security patterns and OWASP guidelines. Triggers on: security review, OWASP, XSS, SQL injection, CSRF, authentication, authorization, secrets management, input validation, secure coding.",
"summary": "Security patterns and OWASP guidelines. Triggers on: security review, OWASP, XSS, SQL injection, CSR...",
"icon": "🛡️",
"version": "1.0.0",
"author": "0xDarkMatter",
"license": "MIT",
"category": "security",
"tags": [
"security",
"owasp",
"authentication",
"authorization",
"secure-coding"
],
"supported_tools": [
"claude",
"codex",
"claude-code"
],
"risk_factors": [
"external_commands",
"network",
"filesystem",
"env_access",
"scripts"
]
},
"security_audit": {
"risk_level": "safe",
"is_blocked": false,
"safe_to_publish": true,
"summary": "This is a legitimate security documentation skill containing educational patterns. The static analyzer flagged 326 issues, but all are false positives triggered by code examples in markdown documentation. The skill provides OWASP Top 10 reference, authentication patterns, input validation examples, and security scanning scripts. No malicious behavior confirmed.",
"risk_factor_evidence": [
{
"factor": "external_commands",
"evidence": [
{
"file": "references/auth-patterns.md",
"line_start": 1,
"line_end": 323
},
{
"file": "references/crypto-patterns.md",
"line_start": 1,
"line_end": 305
},
{
"file": "SKILL.md",
"line_start": 1,
"line_end": 183
}
]
},
{
"factor": "network",
"evidence": [
{
"file": "references/auth-patterns.md",
"line_start": 173,
"line_end": 175
},
{
"file": "references/secure-headers.md",
"line_start": 8,
"line_end": 229
}
]
},
{
"factor": "filesystem",
"evidence": [
{
"file": "scripts/security-scan.sh",
"line_start": 26,
"line_end": 74
},
{
"file": "scripts/dependency-audit.sh",
"line_start": 19,
"line_end": 81
}
]
},
{
"factor": "env_access",
"evidence": [
{
"file": "SKILL.md",
"line_start": 117,
"line_end": 143
},
{
"file": "references/auth-patterns.md",
"line_start": 52,
"line_end": 66
}
]
},
{
"factor": "scripts",
"evidence": [
{
"file": "scripts/security-scan.sh",
"line_start": 1,
"line_end": 89
},
{
"file": "scripts/dependency-audit.sh",
"line_start": 1,
"line_end": 91
}
]
}
],
"critical_findings": [],
"high_findings": [],
"medium_findings": [],
"low_findings": [],
"dangerous_patterns": [],
"files_scanned": 8,
"total_lines": 1820,
"audit_model": "claude",
"audited_at": "2026-01-16T14:17:53.759Z"
},
"content": {
"user_title": "Apply OWASP security patterns",
"value_statement": "Write secure code by applying proven security patterns. This skill provides OWASP Top 10 guidelines, authentication patterns, input validation, and security headers implementation.",
"seo_keywords": [
"security patterns",
"OWASP Top 10",
"secure coding",
"authentication patterns",
"XSS prevention",
"SQL injection",
"security headers",
"Claude Code security",
"Codex security",
"secrets management"
],
"actual_capabilities": [
"Provide OWASP Top 10 vulnerability prevention guidelines",
"Show input validation and output encoding patterns",
"Implement authentication and authorization best practices",
"Generate security header configurations",
"Create secrets management patterns using environment variables",
"Run security scan scripts to detect vulnerabilities"
],
"limitations": [
"Does not execute actual security scans on external code",
"Does not provide penetration testing or exploit verification",
"Does not access external vulnerability databases",
"Patterns are guidance, not a replacement for security review"
],
"use_cases": [
{
"target_user": "Software developers",
"title": "Secure coding guidance",
"description": "Apply OWASP patterns when writing authentication, authorization, and data validation code."
},
{
"target_user": "Security engineers",
"title": "Security documentation",
"description": "Generate security headers, encryption patterns, and compliance documentation for applications."
},
{
"target_user": "DevOps teams",
"title": "Secrets management",
"description": "Implement environment-based secrets handling and security scanning in CI/CD pipelines."
}
],
"prompt_templates": [
{
"title": "OWASP reference",
"scenario": "Get OWASP Top 10 summary",
"prompt": "Show me the OWASP Top 10 with prevention methods for each vulnerability."
},
{
"title": "Input validation",
"scenario": "Learn validation patterns",
"prompt": "Show me input validation patterns to prevent SQL injection and XSS attacks."
},
{
"title": "Security headers",
"scenario": "Configure security headers",
"prompt": "Generate Content-Security-Policy and security headers for a Python Flask application."
},
{
"title": "Auth patterns",
"scenario": "Implement authentication",
"prompt": "Show secure password hashing, JWT token handling, and session management patterns."
}
],
"output_examples": [
{
"input": "How do I prevent SQL injection?",
"output": [
"Use parameterized queries: db.execute('SELECT * WHERE name = ?', [query])",
"Never interpolate user input into SQL strings",
"Validate input type, length, and format before processing",
"Use ORM abstractions when available"
]
},
{
"input": "Generate security headers for Express.js",
"output": [
"Content-Security-Policy: default-src 'self'; script-src 'self'",
"X-Content-Type-Options: nosniff",
"X-Frame-Options: DENY",
"Strict-Transport-Security: max-age=31536000; includeSubDomains"
]
},
{
"input": "Show me password hashing best practices",
"output": [
"Use bcrypt with cost factor 12 or higher",
"Never use MD5 or SHA1 for password hashing",
"Verify passwords with constant-time comparison",
"Store only hashed passwords, never plaintext"
]
}
],
"best_practices": [
"Always validate and sanitize user input on the server side, never trust client-side validation alone",
"Use parameterized queries for database operations to prevent SQL injection attacks",
"Store secrets in environment variables or dedicated secrets managers, never hardcode credentials"
],
"anti_patterns": [
"Using string concatenation or f-strings to build SQL queries with user input",
"Storing API keys, passwords, or tokens directly in source code files",
"Using innerHTML to insert user-generated content without proper escaping"
],
"faq": [
{
"question": "What security patterns does this skill cover?",
"answer": "OWASP Top 10, authentication, authorization, input validation, output encoding, secrets management, and HTTP security headers."
},
{
"question": "Can this skill scan my code for vulnerabilities?",
"answer": "It provides patterns and scripts for security scanning but does not directly analyze your codebase."
},
{
"question": "What languages are supported?",
"answer": "Patterns are language-agnostic with examples in Python, JavaScript, Bash, and configuration formats."
},
{
"question": "Does this skill perform penetration testing?",
"answer": "No, this skill provides security guidance and patterns, not active security testing or exploitation."
},
{
"question": "How do I implement CSP?",
"answer": "Set Content-Security-Policy header with default-src 'self' and restrictive directives for scripts, styles, and connections."
},
{
"question": "What is the recommended password hashing algorithm?",
"answer": "Use bcrypt, argon2, or scrypt with appropriate cost factors. Avoid MD5, SHA1, and SHA256 for passwords."
}
]
},
"file_structure": [
{
"name": "references",
"type": "dir",
"path": "references",
"children": [
{
"name": "auth-patterns.md",
"type": "file",
"path": "references/auth-patterns.md",
"lines": 323
},
{
"name": "crypto-patterns.md",
"type": "file",
"path": "references/crypto-patterns.md",
"lines": 303
},
{
"name": "owasp-detailed.md",
"type": "file",
"path": "references/owasp-detailed.md",
"lines": 330
},
{
"name": "secure-headers.md",
"type": "file",
"path": "references/secure-headers.md",
"lines": 241
}
]
},
{
"name": "scripts",
"type": "dir",
"path": "scripts",
"children": [
{
"name": "dependency-audit.sh",
"type": "file",
"path": "scripts/dependency-audit.sh",
"lines": 91
},
{
"name": "security-scan.sh",
"type": "file",
"path": "scripts/security-scan.sh",
"lines": 90
}
]
},
{
"name": "SKILL.md",
"type": "file",
"path": "SKILL.md",
"lines": 183
}
]
}
Related skills
FAQ
How should passwords be hashed?
Use bcrypt, argon2, or scrypt with a cost factor of 12 or higher.
What input should never be trusted?
URL parameters, form data, HTTP headers, cookies, and file uploads.