OWASP Security Best Practices Skill
Apply these security standards when writing or reviewing code.
Quick Reference: OWASP Top 10:2025
| # | Vulnerability | Key Prevention | |---|---------------|----------------| | A01 | Broken Access Control | Deny by default, enforce server-side, verify ownership | | A02 | Security Misconfiguration | Harden configs, disable defaults, minimize features | | A03 | Supply Chain Failures | Lock versions, verify integrity, audit dependencies | | A04 | Cryptographic Failures | TLS 1.2+, AES-256-GCM, Argon2/bcrypt for passwords | | A05 | Injection | Parameterized queries, input validation, safe APIs | | A06 | Insecure Design | Threat model, rate limit, design security controls | | A07 | Auth Failures | MFA, check breached passwords, secure sessions | | A08 | Integrity Failures | Sign packages, SRI for CDN, safe serialization | | A09 | Logging Failures | Log security events, structured format, alerting | | A10 | Exception Handling | Fail-closed, hide internals, log with context |
Security Code Review Checklist
When reviewing code, check for these issues:
Input Handling
- [ ] All user input validated server-side
- [ ] Using parameterized queries (not string concatenation)
- [ ] Input length limits enforced
- [ ] Allowlist validation preferred over denylist
Authentication & Sessions
- [ ] Passwords hashed with Argon2/bcrypt (not MD5/SHA1)
- [ ] Session tokens have sufficient entropy (128+ bits)
- [ ] Sessions invalidated on logout
- [ ] MFA available for sensitive operations
Access Control
- [ ] Check for framework-level auth middleware (e.g., Next.js middleware.ts, proxy.ts, Express middleware) before flagging missing per-route auth
- [ ] Authorization checked on every request
- [ ] Using object references user cannot manipulate
- [ ] Deny by default policy
- [ ] Privilege escalation paths reviewed
Data Protection
- [ ] Sensitive data encrypted at rest
- [ ] TLS for all data in transit
- [ ] No sensitive data in URLs/logs
- [ ] Secrets in environment/vault (not code)
Error Handling
- [ ] No stack traces exposed to users
- [ ] Fail-closed on errors (deny, not allow)
- [ ] All exceptions logged with context
- [ ] Consistent error responses (no enumeration)
Secure Code Patterns
SQL Injection Prevention
# UNSAFE
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
# SAFE
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
Command Injection Prevention
# UNSAFE
os.system(f"convert {filename} output.png")
# SAFE
subprocess.run(["convert", filename, "output.png"], shell=False)
Password Storage
# UNSAFE
hashlib.md5(password.encode()).hexdigest()
# SAFE
from argon2 import PasswordHasher
PasswordHasher().hash(password)
Access Control
# UNSAFE - No authorization check
@app.route('/api/user/<user_id>')
def get_user(user_id):
return db.get_user(user_id)
# SAFE - Authorization enforced
@app.route('/api/user/<user_id>')
@login_required
def get_user(user_id):
if current_user.id != user_id and not current_user.is_admin:
abort(403)
return db.get_user(user_id)
Error Handling
# UNSAFE - Exposes internals
@app.errorhandler(Exception)
def handle_error(e):
return str(e), 500
# SAFE - Fail-closed, log context
@app.errorhandler(Exception)
def handle_error(e):
error_id = uuid.uuid4()
logger.exception(f"Error {error_id}: {e}")
return {"error": "An error occurred", "id": str(error_id)}, 500
Fail-Closed Pattern
# UNSAFE - Fail-open
def check_permission(user, resource):
try:
return auth_service.check(user, resource)
except Exception:
return True # DANGEROUS!
# SAFE - Fail-closed
def check_permission(user, resource):
try:
return auth_service.check(user, resource)
except Exception as e:
logger.error(f"Auth check failed: {e}")
return False # Deny on error
Agentic AI Security (OWASP 2026)
When building or reviewing AI agent systems, check for:
| Risk | Description | Mitigation | |------|-------------|------------| | ASI01: Goal Hijack | Prompt injection alters agent objectives | Input sanitization, goal boundaries, behavioral monitoring | | ASI02: Tool Misuse | Tools used in unintended ways | Least privilege, fine-grained permissions, validate I/O | | ASI03: Identity & Privilege Abuse | Delegated trust, inherited credentials, role chain exploits | Short-lived scoped tokens, identity verification | | ASI04: Supply Chain | Compromised plugins/MCP servers | Verify signatures, sandbox, allowlist plugins | | ASI05: Code Execution | Unsafe code generation/execution | Sandbox execution, static analysis, human approval | | ASI06: Memory Poisoning | Corrupted RAG/context data | Validate stored content, segment by trust level | | ASI07: Insecure Inter-Agent Comms | Spoofing/intercepting agent-to-agent messages | Authenticate, encrypt, verify message integrity | | ASI08: Cascading Failures | Errors propagate across systems | Circuit breakers, graceful degradation, isolation | | ASI09: Human-Agent Trust Exploitation | Over-trust in agents leveraged to manipulate users | Label AI content, user education, verification steps | | ASI10: Rogue Agents | Compromised agents acting maliciously | Behavior monitoring, kill switches, anomaly detection |
Agent Security Checklist
- [ ] All agent inputs sanitized and validated
- [ ] Tools operate with minimum required permissions
- [ ] Credentials are short-lived and scoped
- [ ] Third-party plugins verified and sandboxed
- [ ] Code execution happens in isolated environments
- [ ] Agent communications authenticated and encrypted
- [ ] Circuit breakers between agent components
- [ ] Human approval for sensitive operations
- [ ] Behavior monitoring for anomaly detection
- [ ] Kill switch available for agent systems
OWASP Top 10 for LLM Applications (2025)
When building or reviewing applications that call LLMs (chatbots, RAG, copilots, agents), check for:
| # | Risk | Key Mitigation | |---|------|----------------| | LLM01 | Prompt Injection | Separate trusted instructions from untrusted data, filter outputs, isolate privileges between user/tool/system context | | LLM02 | Sensitive Information Disclosure | Sanitize training/RAG data, strip PII from context, restrict what the model can retrieve per user | | LLM03 | Supply Chain | Verify model provenance and signatures, vet third-party model hubs, lock model + adapter versions | | LLM04 | Data and Model Poisoning | Validate training/fine-tuning sources, anomaly-detect on data ingestion, hold-out integrity tests | | LLM05 | Improper Output Handling | Treat all LLM output as untrusted input — validate, escape, or sandbox before passing downstream (SQL, shell, HTML, code, tool calls) | | LLM06 | Excessive Agency | Minimize tools and permissions, require human approval for destructive actions, scope credentials per task | | LLM07 | System Prompt Leakage | Never put secrets, keys, or auth logic in the system prompt; assume the prompt is extractable | | LLM08 | Vector and Embedding Weaknesses | Tenant-isolate vector stores, access-control on retrieval, sign or hash chunks against indirect prompt injection | | LLM09 | Misinformation | Cite sources, surface confidence, require grounding for high-stakes answers, disclose AI provenance | | LLM10 | Unbounded Consumption | Rate-limit per user/key, cap tokens and tool calls per request, monitor cost, set hard timeouts |
LLM Application Security Checklist
- [ ] User input never blindly concatenated into a system prompt — use clear delimiters or structured roles
- [ ] LLM output treated as untrusted before reaching a tool, DOM, shell, SQL, or
eval - [ ] Tool/function-calling surface is minimal and least-privilege
- [ ] Destructive or external-effect tools require explicit human approval
- [ ] System prompt contains no secrets, keys, or authorization rules
- [