Move 9 init/seed scripts into scripts/seed/ and 7 validation scripts (+ validators/ subfolder) into scripts/validate/ to reduce clutter in the root scripts/ directory. Update all references across Makefile, CI/CD configs, pre-commit hooks, docs (~40 files), and Python imports. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
13 KiB
Security Rules Reference
This document provides a comprehensive reference for all security rules enforced by the scripts/validate/validate_security.py validator.
Overview
The security validator identifies potential security vulnerabilities and enforces security best practices across the codebase. Rules are organized by category and severity level.
Version: 1.0
Total Rules: 60
Configuration Directory: .security-rules/
Running the Validator
Using Python Directly
# Check all files
python scripts/validate/validate_security.py
# Verbose output
python scripts/validate/validate_security.py -v
# Errors only
python scripts/validate/validate_security.py --errors-only
# JSON output (for CI/CD)
python scripts/validate/validate_security.py --json
Using the Unified Validator
# Run security checks only
python scripts/validate/validate_all.py --security
# Run all validators
python scripts/validate/validate_all.py
Severity Levels
| Severity | Description | Exit Code | Action Required |
|---|---|---|---|
| Error | Critical security vulnerability | 1 | Must fix immediately |
| Warning | Security concern | 0 | Should fix |
| Info | Security suggestion | 0 | Consider implementing |
Authentication Rules (SEC-001 to SEC-010)
SEC-001: No Hardcoded Credentials
Severity: Error
Credentials must never be hardcoded in source code. Use environment variables or secret management.
# Bad
api_key = "sk-1234567890abcdef"
password = "admin123"
# Good
api_key = os.environ.get("API_KEY")
password = settings.admin_password
SEC-002: JWT Expiry Enforcement
Severity: Error
All JWT tokens must have expiration claims. Access tokens should expire in 15-60 minutes.
SEC-003: Password Hashing Required
Severity: Error
Passwords must be hashed using bcrypt, argon2, or scrypt. Never store or compare passwords in plain text.
# Bad
if user.password == password:
...
# Good
if bcrypt.checkpw(password.encode(), user.hashed_password):
...
SEC-004: Session Regeneration After Auth
Severity: Warning
Session IDs should be regenerated after authentication to prevent session fixation attacks.
SEC-005: Brute Force Protection
Severity: Warning
Login endpoints should implement rate limiting or account lockout after failed attempts.
SEC-006: Secure Password Reset
Severity: Warning
Password reset tokens must be cryptographically random, expire within 1 hour, and be single-use.
SEC-007: Authentication on Sensitive Endpoints
Severity: Error
All endpoints except public ones must require authentication.
SEC-008: Token in Authorization Header
Severity: Warning
JWT tokens should be sent in Authorization header, not in URL parameters.
SEC-009: Logout Invalidates Tokens
Severity: Warning
Logout should invalidate or blacklist tokens.
SEC-010: Multi-Factor Authentication Support
Severity: Info
Consider implementing MFA for sensitive operations.
Injection Prevention Rules (SEC-011 to SEC-020)
SEC-011: No Raw SQL Queries
Severity: Error
Use SQLAlchemy ORM or parameterized queries only. Never concatenate user input into SQL strings.
# Bad
db.execute(f"SELECT * FROM users WHERE name = '{name}'")
# Good
db.query(User).filter(User.name == name)
SEC-012: No Shell Command Injection
Severity: Error
Never use shell=True with subprocess. Use subprocess with list arguments.
# Bad
subprocess.run(f"convert {filename}", shell=True)
os.system(f"rm {filename}")
# Good
subprocess.run(["convert", filename])
SEC-013: No Code Execution
Severity: Error
Never use eval() or exec() with user input.
SEC-014: Path Traversal Prevention
Severity: Error
Validate file paths to prevent directory traversal. Use secure_filename() for uploads.
# Bad
path = f"/uploads/{filename}"
# Good
from werkzeug.utils import secure_filename
path = f"/uploads/{secure_filename(filename)}"
SEC-015: XSS Prevention in Templates
Severity: Error
Use safe output methods in templates. Prefer x-text over x-html in Alpine.js.
<!-- Bad - vulnerable to XSS -->
<div x-html="userInput"></div>
<!-- Good - safe from XSS -->
<div x-text="userInput"></div>
SEC-016: LDAP Injection Prevention
Severity: Error
Escape special characters in LDAP queries.
SEC-017: XML External Entity Prevention
Severity: Error
Disable external entities when parsing XML. Use defusedxml.
# Bad
import xml.etree.ElementTree as ET
tree = ET.parse(user_file)
# Good
import defusedxml.ElementTree as ET
tree = ET.parse(user_file)
SEC-018: Template Injection Prevention
Severity: Error
Never render user input as template code.
SEC-019: SSRF Prevention
Severity: Warning
Validate URLs before making external requests. Whitelist allowed domains.
SEC-020: Deserialization Safety
Severity: Error
Never deserialize untrusted data with pickle. Use yaml.safe_load() instead of yaml.load().
# Bad
data = pickle.loads(user_data)
config = yaml.load(user_config)
# Good
config = yaml.safe_load(user_config)
data = json.loads(user_data)
Data Protection Rules (SEC-021 to SEC-030)
SEC-021: PII Logging Prevention
Severity: Error
Never log passwords, tokens, credit cards, or sensitive PII.
# Bad
logger.info(f"User login: {username}, password: {password}")
# Good
logger.info(f"User login: {username}")
SEC-022: Sensitive Data in URLs
Severity: Error
Sensitive data should not appear in URL query parameters. Use POST body or headers instead.
SEC-023: Mass Assignment Prevention
Severity: Warning
Use explicit field assignment, not **kwargs from user input.
# Bad
user = User(**request.json)
# Good
user = User(
name=request.json.get("name"),
email=request.json.get("email")
)
SEC-024: Error Message Information Leakage
Severity: Error
Error messages should not reveal internal details. No stack traces to users.
SEC-025: Secure Cookie Settings
Severity: Error
Cookies must have Secure, HttpOnly, SameSite attributes.
SEC-026: Encryption for Sensitive Data at Rest
Severity: Info
Consider encrypting sensitive data stored in the database.
SEC-027: Data Retention Limits
Severity: Info
Implement data retention policies.
SEC-028: Response Data Filtering
Severity: Warning
API responses should not include sensitive internal fields. Use Pydantic response models.
SEC-029: File Upload Validation
Severity: Error
Validate uploaded files by extension AND content type. Limit file size.
SEC-030: Backup Encryption
Severity: Info
Database backups should be encrypted.
API Security Rules (SEC-031 to SEC-040)
SEC-031: CORS Origin Validation
Severity: Error
CORS must not allow all origins in production. Specify allowed origins explicitly.
# Bad
allow_origins=["*"]
# Good
allow_origins=["https://example.com", "https://api.example.com"]
SEC-032: Rate Limiting on Sensitive Endpoints
Severity: Warning
Auth, password reset, and payment endpoints need rate limiting.
SEC-033: Security Headers
Severity: Warning
Configure security headers like X-Content-Type-Options, X-Frame-Options, Content-Security-Policy.
SEC-034: HTTPS Enforcement
Severity: Error
External URLs must use HTTPS. HTTP is only acceptable for localhost.
SEC-035: Request Size Limits
Severity: Warning
Limit request body size to prevent DoS attacks.
SEC-036: Input Validation with Pydantic
Severity: Warning
All API inputs should be validated using Pydantic models.
SEC-037: API Versioning
Severity: Info
APIs should be versioned for security update isolation.
SEC-038: Method Restrictions
Severity: Warning
Endpoints should only allow necessary HTTP methods.
SEC-039: Authentication Bypass Prevention
Severity: Error
Ensure authentication cannot be bypassed.
SEC-040: Timeout Configuration
Severity: Warning
All external calls must have timeouts configured.
Cryptography Rules (SEC-041 to SEC-050)
SEC-041: Strong Hashing Algorithms
Severity: Error
Use bcrypt, argon2, scrypt for passwords. Use SHA-256 or stronger for general hashing. Never use MD5 or SHA1.
# Bad
import hashlib
password_hash = hashlib.md5(password.encode()).hexdigest()
# Good
import bcrypt
password_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
SEC-042: Secure Random Generation
Severity: Error
Use the secrets module for security-sensitive randomness. Never use random module for tokens or keys.
# Bad
import random
token = ''.join(random.choices(string.ascii_letters, k=32))
# Good
import secrets
token = secrets.token_urlsafe(32)
SEC-043: No Hardcoded Encryption Keys
Severity: Error
Encryption keys must come from environment variables or secret management services.
SEC-044: Strong Encryption Algorithms
Severity: Error
Use AES-256 or ChaCha20. Never use DES, 3DES, or RC4.
SEC-045: Proper IV/Nonce Usage
Severity: Error
Encryption IVs and nonces must be randomly generated and unique per encryption.
SEC-046: TLS Version Requirements
Severity: Warning
Enforce TLS 1.2 or higher. Disable SSLv2, SSLv3, TLS 1.0, TLS 1.1.
SEC-047: Certificate Verification
Severity: Error
Always verify SSL certificates. Never disable verification in production.
# Bad
requests.get(url, verify=False)
# Good
requests.get(url, verify=True)
SEC-048: Key Derivation for Passwords
Severity: Warning
When deriving encryption keys from passwords, use PBKDF2 with 100K+ iterations, Argon2, or scrypt.
SEC-049: Secure Key Storage
Severity: Info
Encryption keys should be stored in environment variables, secret management, or HSMs.
SEC-050: Key Rotation Support
Severity: Info
Implement key rotation with multiple key versions.
Audit & Logging Rules (SEC-051 to SEC-060)
SEC-051: Authentication Event Logging
Severity: Warning
Log authentication events including successful logins, failed attempts, logouts, and password changes.
SEC-052: Admin Action Audit Trail
Severity: Warning
All admin operations should be logged with admin user ID, action performed, target resource, timestamp, and IP address.
SEC-053: Data Modification Logging
Severity: Info
Log create/update/delete on sensitive data like user accounts, roles, financial transactions, and configuration changes.
SEC-054: Security Event Logging
Severity: Warning
Log security-relevant events like authorization failures, input validation failures, rate limit triggers, and suspicious activity.
SEC-055: Log Injection Prevention
Severity: Warning
Sanitize user input before logging. Newlines and control characters can corrupt logs.
# Bad
logger.info(f"User search: {request.query}")
# Good
logger.info(f"User search: {request.query!r}") # repr escapes
SEC-056: Centralized Logging
Severity: Info
Use centralized logging for correlation across services, tamper-evident storage, and alerting.
SEC-057: Log Level Appropriateness
Severity: Info
Use appropriate log levels: ERROR for security failures, WARNING for suspicious activity, INFO for successful events.
SEC-058: Structured Logging Format
Severity: Info
Use structured logging (JSON) for easy parsing and searchability.
SEC-059: Audit Log Integrity
Severity: Info
Protect audit logs from tampering with append-only storage and cryptographic chaining.
SEC-060: Privacy-Aware Logging
Severity: Warning
Comply with data protection regulations. No PII in logs without consent.
Configuration
All rules are defined in .security-rules/ directory:
.security-rules/
├── _main.yaml # Main configuration
├── authentication.yaml # SEC-001 to SEC-010
├── injection.yaml # SEC-011 to SEC-020
├── data_protection.yaml # SEC-021 to SEC-030
├── api_security.yaml # SEC-031 to SEC-040
├── cryptography.yaml # SEC-041 to SEC-050
└── audit.yaml # SEC-051 to SEC-060
Suppressing Rules
Use noqa comments to suppress specific rules:
# noqa: SEC-001 - This is a test file with intentional test credentials
test_password = "test123"
Related Documentation
Summary Statistics
| Category | Rules | Errors | Warnings | Info |
|---|---|---|---|---|
| Authentication | 10 | 4 | 5 | 1 |
| Injection Prevention | 10 | 9 | 1 | 0 |
| Data Protection | 10 | 4 | 3 | 3 |
| API Security | 10 | 4 | 5 | 1 |
| Cryptography | 10 | 6 | 2 | 2 |
| Audit & Logging | 10 | 0 | 5 | 5 |
| Total | 60 | 27 | 21 | 12 |
Last Updated: 2025-12-21 Version: 1.0