Skill
·
v1.0.0
·
MIT
security-audit
Perform an OWASP-flavored security review focused on input handling, authentication, authorization, secrets, and dependencies. Use when the user asks for a security audit, threat review, vulnerability check, or wants to harden code before release.
elyra ›
/skills install security-audit
A pragmatic, OWASP-flavored review. The goal is finding real risks, not generating a checklist that nobody acts on.
When to use
- "Audit X for security issues"
- "Review this code for vulnerabilities"
- "Is this safe to deploy?"
- "Harden the auth flow"
- "Check for secrets / OWASP issues"
Scope this first
Security is infinite; your time is not. Ask:
- What are you protecting? Data (PII, payments, secrets)? Availability? Integrity?
- Who's the threat model? Anonymous internet, authenticated users, malicious insiders, supply chain?
- What's in scope this round? Whole repo, one module, the auth surface, the public API?
If the user can't answer, suggest starting with the public attack surface (anything reachable without auth) and secret handling.
Procedure
- Inventory the attack surface — public endpoints, file uploads, deserialization points, command/SQL/template execution, third-party callbacks
- Walk the checklist below, category by category
- For each finding: confirm it's exploitable (or be honest that it's theoretical), estimate severity, propose a fix
- Report by severity (see Output format)
Checklist
Input handling
- Every external input has explicit validation (type, length, range, format)
- User input never built into SQL via string concat → parameterized queries only
- User input never passed to
eval,exec,Function(),system(), shell, deserializer - Path inputs are normalized and checked against a base directory (no
../traversal) - Uploaded files: type checked by content, not extension; stored outside web root; size-limited; renamed
- Rendered output is context-correctly escaped (HTML / JS / URL / SQL / shell each need their own escaper)
- No regex with catastrophic backtracking on user input (ReDoS)
- XML/YAML parsers disable external entities and unsafe loaders
AuthN (authentication)
- Passwords hashed with
argon2,bcrypt, orscrypt— never MD5/SHA1/SHA256-only - Login is rate-limited and lockout/back-off is implemented
- Session tokens are long, random, server-side invalidatable
- Cookies:
HttpOnly,Secure,SameSite=LaxorStrict - Password reset tokens are single-use, short-lived, and tied to user + email
- MFA available for sensitive accounts
- Logout actually invalidates the session server-side
AuthZ (authorization)
- Every endpoint checks "is this user allowed to do this to this resource?"
- No relying on hidden fields / client-supplied IDs /
refererheaders for permissions - Object-level authorization (IDOR) checked:
GET /orders/42verifies 42 belongs to the caller - Admin-only actions checked on server, not just hidden in UI
- Multi-tenant boundaries enforced in every query
Secrets
- No secrets in source, history, CI logs, error responses, or client bundles
- Secrets loaded from env / secret manager / vault — not files in the repo
-
.env,.pem, key material in.gitignore - Rotate-able: nothing baked in at build time that can't be changed
- Quick scan:
git log -p -S 'BEGIN PRIVATE KEY',grep -RIn 'api[_-]\?key\|secret\|password' .
Transport & headers
- HTTPS enforced (redirect from HTTP, HSTS header)
- CORS configured intentionally (no
Access-Control-Allow-Origin: *for credentialed APIs) -
Content-Security-Policyset -
X-Frame-Optionsor CSPframe-ancestors -
Referrer-Policy: strict-origin-when-cross-originor stricter
CSRF / SSRF
- State-changing requests require CSRF token or are
SameSite+ auth-header-based - Outbound requests to user-supplied URLs are blocked from internal ranges (169.254, 127.0.0.0/8, 10/8, 192.168/16, ::1) and metadata endpoints (
169.254.169.254)
Dependencies & supply chain
- Lockfile committed
- Audit tool run cleanly:
npm audit,pnpm audit,composer audit,pip-audit,cargo audit,bundle audit - No abandoned/unmaintained critical deps
- CI/build secrets scoped (no admin-level GitHub tokens in PR builds from forks)
- Pinned third-party CDN scripts use SRI
Logging & errors
- No secrets, passwords, tokens, or PII in logs
- No stack traces leaked to end users in production
- Errors return generic messages externally, full detail internally
- Audit log for sensitive actions (login, role change, payment, deletion)
Data
- PII encrypted at rest where regulation requires
- Backups exist and have been restored at least once
- Deletes are real deletes (or documented soft-delete with retention policy)
- Database access uses least-privilege accounts (the app doesn't connect as DB owner)
Quick scans to run
# Hardcoded secrets (rough)
grep -RInE '(api[_-]?key|secret|password|token)\s*[:=]\s*["'\''][^"'\'']{6,}' \
--include='*.{js,ts,jsx,tsx,php,py,rb,go,rs,java,kt,yml,yaml,env}' .
# Private key material
grep -RIn 'BEGIN .* PRIVATE KEY' .
# Eval-like primitives
grep -RInE '\b(eval|exec|Function|setTimeout|setInterval)\s*\(' --include='*.{js,ts}' .
# Raw SQL concatenation (heuristic, lots of false positives)
grep -RInE 'SELECT .*\+ .*\bFROM|"\s*\+\s*\$|f"SELECT.*\{' .
# Dependency audit (pick what applies)
npm audit --omit=dev || pnpm audit || composer audit || pip-audit || cargo audit
Treat all greps as leads, not verdicts.
Severity rubric
| Tag | Meaning |
|---|---|
| 🔴 Critical | Remote exploit possible by unauthenticated user; data loss; account takeover. Fix before next deploy. |
| 🟠 High | Exploit possible by authenticated user, or critical with significant preconditions. Fix this sprint. |
| 🟡 Medium | Defense-in-depth gap, hardening recommendation, theoretical exploit. |
| 🟢 Low | Best-practice nit, not directly exploitable. |
| 💭 Question | Looks suspicious but you need more context to be sure. |
Output format
## Security audit: <scope>
**Threat model assumed:** <e.g. "anonymous internet attacker against public API">
**Scanned:** <files / modules / endpoints>
### 🔴 Critical
- `path/to/file.ts:42` — <finding>. **Exploit:** <how>. **Fix:** <what>.
### 🟠 High
- …
### 🟡 Medium
- …
### 🟢 Low
- …
### 💭 Questions
- …
### ✅ Looked at and clean
- <category> — <one sentence on what you verified>
Anti-patterns
- ❌ "Looks fine 👍" — say what you actually checked
- ❌ Crying wolf — marking every finding "critical" devalues real ones
- ❌ Listing CVEs from
npm auditwithout checking if the vulnerable path is reachable - ❌ Recommending
DOMPurify/helmet/ a WAF as the only fix to an injection bug — fix the root cause too - ❌ Suggesting custom crypto. Don't.
Useful references
- OWASP Top 10
- OWASP ASVS — exhaustive checklist
- OWASP Cheat Sheet Series — practical, per-topic