security

Version: 1.0 Source: Security Standards

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "security" with this command: npx skills add alexanderstephenthompson/claude-hub/alexanderstephenthompson-claude-hub-security

Security Skill

Version: 1.0 Source: Security Standards

Security must be built in from the start, not bolted on later. These standards apply to all code that handles user data, authentication, or external input.

Core Principles

  • Security by Design — Build security in from the start, not as an afterthought

  • Defense in Depth — Multiple layers of security; no single point of failure

  • Least Privilege — Grant minimum access required for the task

  • Fail Securely — Errors should not expose vulnerabilities or sensitive data

  • Zero Trust — Never trust input, always verify

  • Assume Breach — Design as if attackers will get in; minimize blast radius

OWASP Top 10 (2021)

Critical vulnerabilities to prevent:

Vulnerability Prevention

1 Broken Access Control Check authorization on every request

2 Cryptographic Failures Use strong encryption, never roll your own

3 Injection Parameterized queries, input validation

4 Insecure Design Threat modeling, secure architecture

5 Security Misconfiguration Secure defaults, proper error handling

6 Vulnerable Components Keep dependencies updated, audit regularly

7 Auth Failures Strong auth, MFA, secure session management

8 Integrity Failures Verify code/data integrity, sign releases

9 Logging Failures Log security events, protect log data

10 SSRF Validate and allowlist server-side URLs

Input Validation

The Golden Rule

Never trust user input. All input is potentially malicious.

Validation Strategy

  1. Validate → 2. Sanitize → 3. Encode (for output context)

SQL Injection Prevention

❌ NEVER - String concatenation

query = f"SELECT * FROM users WHERE id = {user_id}"

✅ ALWAYS - Parameterized queries

cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))

✅ ALWAYS - ORM with parameters

User.objects.filter(id=user_id)

XSS Prevention

// ❌ NEVER - Direct HTML insertion element.innerHTML = userInput; document.write(userInput);

// ✅ ALWAYS - Text content (auto-escapes) element.textContent = userInput;

// ✅ ALWAYS - Template literals with escaping const escaped = escapeHtml(userInput);

Command Injection Prevention

❌ NEVER - Shell execution with user input

os.system(f"ls {user_path}") subprocess.call(f"convert {filename}", shell=True)

✅ ALWAYS - Argument arrays (no shell)

subprocess.run(["ls", user_path], shell=False) subprocess.run(["convert", filename], shell=False)

Input Validation Patterns

import re

def validate_email(email: str) -> bool: """Validate email format.""" pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$' return bool(re.match(pattern, email)) and len(email) <= 254

def validate_username(username: str) -> bool: """Validate username: alphanumeric, 3-30 chars.""" pattern = r'^[a-zA-Z0-9_]{3,30}$' return bool(re.match(pattern, username))

def validate_url(url: str, allowed_domains: list[str]) -> bool: """Validate URL against allowlist.""" from urllib.parse import urlparse parsed = urlparse(url) return ( parsed.scheme in ('http', 'https') and parsed.netloc in allowed_domains )

Authentication & Authorization

Password Requirements

Requirement Minimum

Length 12 characters

Complexity Not required if length met

Common passwords Block top 10,000

Breached passwords Check against HaveIBeenPwned

Password Storage

✅ Use bcrypt, Argon2, or scrypt

import bcrypt

def hash_password(password: str) -> bytes: """Hash password with bcrypt.""" salt = bcrypt.gensalt(rounds=12) return bcrypt.hashpw(password.encode(), salt)

def verify_password(password: str, hashed: bytes) -> bool: """Verify password against hash.""" return bcrypt.checkpw(password.encode(), hashed)

NEVER:

  • Store passwords in plain text

  • Use MD5 or SHA1 for passwords

  • Roll your own hashing

Session Management

Session security settings

SESSION_CONFIG = { "cookie_secure": True, # HTTPS only "cookie_httponly": True, # No JavaScript access "cookie_samesite": "Lax", # CSRF protection "session_lifetime": 3600, # 1 hour max "regenerate_on_login": True # Prevent session fixation }

Authorization Checks

✅ Check authorization on EVERY request

def get_document(user, document_id): document = Document.get(document_id)

# Always verify ownership/access
if document.owner_id != user.id and not user.is_admin:
    raise PermissionError("Access denied")

return document

Data Protection

Encryption Requirements

Data Type At Rest In Transit

Passwords Hashed (bcrypt/Argon2) TLS 1.2+

PII (name, email, address) AES-256 TLS 1.2+

Payment data AES-256 + PCI DSS TLS 1.3

Health data AES-256 + HIPAA TLS 1.3

Session tokens N/A TLS 1.2+

API keys AES-256 TLS 1.2+

Sensitive Data Handling

✅ Mask sensitive data in logs

def log_user_action(user, action, data): safe_data = { "user_id": user.id, "email": mask_email(user.email), # j***@example.com "action": action, # Never log: passwords, tokens, full credit cards } logger.info("User action", extra=safe_data)

def mask_email(email: str) -> str: """Mask email for logging.""" local, domain = email.split("@") return f"{local[0]}***@{domain}"

def mask_card(card: str) -> str: """Show only last 4 digits.""" return f"--****-{card[-4:]}"

Data Retention

  • Delete data when no longer needed

  • Implement data expiration policies

  • Provide user data export/deletion (GDPR)

  • Securely wipe deleted data (not just mark deleted)

API Security

Rate Limiting

Implement rate limiting per endpoint

RATE_LIMITS = { "/api/login": "5/minute", # Prevent brute force "/api/register": "3/minute", # Prevent spam "/api/password-reset": "3/hour", "/api/*": "100/minute", # General limit }

CORS Configuration

✅ Specific origins only

CORS_CONFIG = { "origins": [ "https://app.example.com", "https://admin.example.com", ], "methods": ["GET", "POST", "PUT", "DELETE"], "allow_credentials": True, "max_age": 3600, }

❌ NEVER in production

CORS_CONFIG = { "origins": "*", # Allows any origin! }

API Response Security

❌ Never expose internal errors

def handle_error(error): # Don't send: stack traces, SQL errors, file paths return {"error": "An error occurred"}, 500

✅ Log details, return generic message

def handle_error(error): logger.error(f"Internal error: {error}", exc_info=True) return {"error": "Internal server error"}, 500

Security Headers

SECURITY_HEADERS = { "Strict-Transport-Security": "max-age=31536000; includeSubDomains", "X-Content-Type-Options": "nosniff", "X-Frame-Options": "DENY", "X-XSS-Protection": "1; mode=block", "Content-Security-Policy": "default-src 'self'", "Referrer-Policy": "strict-origin-when-cross-origin", }

Secrets Management

Environment Variables

✅ Store secrets in environment

export DATABASE_URL="postgres://..." export API_KEY="..." export JWT_SECRET="..."

❌ NEVER commit secrets to code

DATABASE_URL = "postgres://user:password@host/db" # In code!

Secret Requirements

Secret Type Rotation Period Storage

API keys 90 days Vault/env vars

Database passwords 90 days Vault/env vars

JWT secrets 30 days Vault/env vars

Encryption keys 1 year HSM/KMS

User passwords On compromise Hashed in DB

.gitignore

Secrets - NEVER commit

.env .env.local .env.*.local *.pem .key credentials.json secrets.yaml config/secrets/

File Upload Security

Validation Checklist

def validate_upload(file) -> bool: """Validate uploaded file."""

# 1. Check file size
MAX_SIZE = 10 * 1024 * 1024  # 10MB
if file.size > MAX_SIZE:
    raise ValueError("File too large")

# 2. Check extension against allowlist
ALLOWED_EXTENSIONS = {'.jpg', '.jpeg', '.png', '.pdf'}
ext = Path(file.name).suffix.lower()
if ext not in ALLOWED_EXTENSIONS:
    raise ValueError("File type not allowed")

# 3. Verify magic bytes (don't trust extension)
magic_bytes = file.read(8)
file.seek(0)
if not is_valid_magic(magic_bytes, ext):
    raise ValueError("File content doesn't match extension")

# 4. Generate safe filename
safe_name = generate_safe_filename(file.name)

# 5. Store outside web root
storage_path = UPLOAD_DIR / safe_name  # Not in /public!

return True

Safe Filename Generation

import uuid import re from pathlib import Path

def generate_safe_filename(original: str) -> str: """Generate safe filename, preserving extension.""" ext = Path(original).suffix.lower() # Use UUID, not original filename return f"{uuid.uuid4()}{ext}"

Logging & Monitoring

What to Log

✅ Log these security events

SECURITY_EVENTS = [ "login_success", "login_failure", "logout", "password_change", "password_reset_request", "permission_denied", "invalid_token", "rate_limit_exceeded", "suspicious_input", "admin_action", ]

What NOT to Log

❌ NEVER log these

NEVER_LOG = [ "password", "password_hash", "credit_card", "ssn", "api_key", "session_token", "jwt_token", "private_key", ]

Structured Security Logging

def log_security_event(event_type: str, user_id: str, details: dict): """Log security event with context.""" logger.info("security_event", extra={ "event_type": event_type, "user_id": user_id, "timestamp": datetime.utcnow().isoformat(), "ip_address": get_client_ip(), "user_agent": get_user_agent(), **sanitize_details(details), })

Security Checklist

Before Every Release

  • No secrets in code or version control

  • All user input validated and sanitized

  • SQL queries use parameterized statements

  • Authentication on all protected endpoints

  • Authorization checks on all resources

  • HTTPS enforced (no HTTP)

  • Security headers configured

  • Rate limiting in place

  • Error messages don't leak sensitive info

  • Dependencies updated and audited

  • File uploads validated and stored safely

  • Logging captures security events

  • CORS configured restrictively

Code Review Security Focus

  • Input validation at all entry points

  • Output encoding for XSS prevention

  • Access control checks present

  • No hardcoded secrets

  • Proper error handling (no stack traces)

  • Secure defaults used

  • Third-party libraries are necessary and trusted

Enforced Rules

These rules are deterministically checked by check.js (clean-team). When updating these standards, update the corresponding check.js rules to match — and vice versa.

Rule ID Severity What It Checks

no-document-write

error document.write() usage (DOM injection risk)

no-hardcoded-secrets

error API keys, tokens, passwords in string literals

no-innerHTML

warn .innerHTML assignment (XSS risk)

References

  • references/owasp-top-10.md — Detailed OWASP vulnerability guide

  • references/input-validation.md — Complete input validation patterns

  • references/auth-patterns.md — Authentication and authorization patterns

Assets

  • assets/security-checklist.md — Pre-release security checklist

  • assets/threat-model-template.md — Threat modeling template

Scripts

  • scripts/scan_secrets.py — Scan code for accidentally committed secrets

  • scripts/check_dependencies.py — Check dependencies for known vulnerabilities

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.