Instal·la
npx skillscat add saajunaid/caddis-plugin/security-review Instal·la des del registre de SkillsCat.
SKILL.md
Security Review
On Claude Code, prefer the native
/security-review. It is a command, not a skill, so it always
fires — including headless — and it has grown capabilities this one does not have: Reach for it first.This surface remains because caddis ships to harnesses that have no native equivalent — agy,
Codex and Copilot. There it is the only review you get. Do not delete it to tidy up Claude Code.
/caddis:cross-reviewis NOT replaced by either. It sends the diff to a different vendor's
model, which neither this nor the native reviewer can do.
Security review workflow covering OWASP Top 10, code scanning, and cloud infrastructure.
When to Use
- Implementing authentication or authorization
- Handling user input or file uploads
- Creating or modifying API endpoints
- Working with secrets, deploying to cloud, or configuring CI/CD
Phase 1: OWASP Top 10 Checks
A01 — Broken Access Control
# BAD — no auth check
@app.route("/admin/users")
def list_users():
return db.query(User).all()
# GOOD
@app.route("/admin/users")
@require_role("admin")
def list_users():
return db.query(User).all()- Every endpoint checks authentication
- Role-based access control enforced
- Users cannot access other users' data (IDOR)
A02 — Cryptographic Failures
# BAD: password_hash = hashlib.md5(password.encode()).hexdigest()
# GOOD:
from passlib.hash import argon2
password_hash = argon2.hash(password)- Passwords hashed with bcrypt/argon2
- Sensitive data encrypted at rest and in transit
- No secrets in source code or logs
A03 — Injection
# BAD: cursor.execute(f"SELECT * FROM users WHERE email = '{email}'")
# GOOD:
cursor.execute("SELECT * FROM users WHERE email = %s", (email,))- All queries parameterized or use ORM
- No
eval(),exec(), oros.system()with user input
A05 — Security Misconfiguration
- Debug mode disabled in production
- Default credentials changed
- Unnecessary endpoints disabled
A06 — Vulnerable Components
pip audit # Python
npm audit # JavaScript
trivy image app # Container- No known vulnerabilities; lock files committed
A07 — Authentication Failures
- Session tokens in httpOnly cookies (not localStorage)
- Account lockout after failed attempts
- MFA for privileged accounts
A09 — Logging Failures
# BAD: logger.info(f"Login: user={email}, password={password}")
# GOOD: logger.info(f"Login: user={email}, success={is_valid}")- Auth events logged; no PII or secrets in logs
A10 — SSRF
ALLOWED_HOSTS = {"api.example.com"}
parsed = urlparse(user_url)
if parsed.hostname not in ALLOWED_HOSTS:
raise ValueError("URL not allowed")Phase 2: Input Validation
from pydantic import BaseModel, EmailStr, constr, conint
class CreateUserRequest(BaseModel):
email: EmailStr
name: constr(min_length=1, max_length=100)
age: conint(ge=0, le=150)
# Validate
try:
data = CreateUserRequest(**request_json)
except ValidationError as e:
return {"error": e.errors()}, 400File uploads: check size, extension, and magic bytes.
Phase 3: Security Headers
@app.after_request
def add_security_headers(response):
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
response.headers["Content-Security-Policy"] = (
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'"
)
return responsePhase 4: Cloud Infrastructure
IAM — Least Privilege
# GOOD: specific permissions on specific resources
permissions: [s3:GetObject, s3:ListBucket]
resources: [arn:aws:s3:::my-bucket/*]
# BAD: permissions: [s3:*], resources: ["*"]- No root account in production; MFA on privileged accounts
- Service accounts use roles, not long-lived keys
Secrets Management
- Secrets in a manager (AWS SM, Vault) with rotation
- No secrets in env vars without rotation policy
CI/CD Security
jobs:
deploy:
permissions: { contents: read }
steps:
- uses: actions/checkout@v4
- uses: trufflesecurity/trufflehog@main # Secret scanning
- run: pip audit # Dep audit
- run: pytest --cov=myapp --cov-fail-under=80- OIDC instead of long-lived credentials
- Branch protection and code review required
Network
- Database not publicly accessible
- Security groups follow least privilege
- WAF enabled
Pre-Deployment Checklist
- No hardcoded secrets
- All user inputs validated server-side
- All queries parameterized
- Auth + authz on every endpoint
- Rate limiting enabled
- HTTPS enforced
- Security headers configured
- No sensitive data in error responses or logs
- Dependencies audited
- Cloud IAM least-privilege applied
- Backups automated with tested recovery