When to use
Use this before merging security-sensitive changes, when reviewing untrusted or legacy code, or during a scheduled appsec pass. The goal is to find defensive weaknesses and recommend fixes.
Not for: writing working exploits or PoCs; scanning dependencies for CVEs (use sec-dependency-audit); or architecture-level risk enumeration (use sec-threat-model). Review the code you can read — do not attack a running system.
Method
- Map inputs and sinks. Trace where external data enters (requests, files, env, messages) and where it reaches dangerous sinks (SQL, shell, eval, file paths, HTML, deserializers, template engines).
- Injection. Confirm parameterized queries, escaped output, allow-listed commands, and safe path joins. Decision point: any string-concatenated query, shell call, or dynamic template is a finding until proven safe.
- AuthN/AuthZ. Verify every privileged action checks identity AND permission server-side. Hunt for missing checks, IDOR (object references without ownership checks), and client-trusted roles.
- Secrets. Look for hardcoded keys, tokens, passwords, and any secret written to logs or returned to clients. Confirm secrets load from config or a vault.
- Deserialization & parsing. Flag unsafe deserialization (pickle, native serialize, YAML unsafe load), XXE-prone XML parsers, and prototype pollution.
- Crypto & sessions. Decision point: if you see a hand-rolled cipher, MD5/SHA1 for passwords, or a predictable token, escalate to Critical and stop to confirm blast radius before continuing.
Example
In getInvoice(req) you find db.query("SELECT * FROM invoices WHERE id=" + req.params.id). Finding: SQL injection, Critical, invoice.js:42, category Injection. Fix: use a parameterized query — db.query("SELECT * FROM invoices WHERE id=?", [req.params.id]). Also note the missing ownership check (IDOR) — any user can read any invoice id.
Pitfalls
- Grepping for
eval and stopping. Real injection hides behind wrappers and helpers; follow the data, not the keyword.
- Reporting without a fix. A finding with no concrete remediation gets ignored. Always include the corrected pattern.
- Trusting framework defaults blindly. ORMs and templates have raw-query and raw-HTML escape hatches; check whether they are used.
- Severity inflation. Marking everything Critical trains reviewers to ignore you. Rank honestly by impact and reachability.
Output format
## Summary
Files reviewed: <list>. Overall risk posture: <sentence>.
## Findings
| Severity | File:line | Category | Description | Recommended fix |
|----------|-----------|----------|-------------|-----------------|
## Quick wins
- <low-effort, high-value fix>
## Follow-ups
- <needs design change or owner decision>
1---2name: sec-code-audit3description: Perform a defensive, security-focused code audit covering injection, authorization, secrets, unsafe deserialization, and crypto.4---56## When to use78Use this before merging security-sensitive changes, when reviewing untrusted or legacy code, or during a scheduled appsec pass. The goal is to find defensive weaknesses and recommend fixes.910**Not for:** writing working exploits or PoCs; scanning dependencies for CVEs (use `sec-dependency-audit`); or architecture-level risk enumeration (use `sec-threat-model`). Review the code you can read — do not attack a running system.1112## Method13141. **Map inputs and sinks.** Trace where external data enters (requests, files, env, messages) and where it reaches dangerous sinks (SQL, shell, eval, file paths, HTML, deserializers, template engines).152. **Injection.** Confirm parameterized queries, escaped output, allow-listed commands, and safe path joins. *Decision point:* any string-concatenated query, shell call, or dynamic template is a finding until proven safe.163. **AuthN/AuthZ.** Verify every privileged action checks identity AND permission server-side. Hunt for missing checks, IDOR (object references without ownership checks), and client-trusted roles.174. **Secrets.** Look for hardcoded keys, tokens, passwords, and any secret written to logs or returned to clients. Confirm secrets load from config or a vault.185. **Deserialization & parsing.** Flag unsafe deserialization (pickle, native serialize, YAML unsafe load), XXE-prone XML parsers, and prototype pollution.196. **Crypto & sessions.** *Decision point:* if you see a hand-rolled cipher, MD5/SHA1 for passwords, or a predictable token, escalate to Critical and stop to confirm blast radius before continuing.2021## Example2223In `getInvoice(req)` you find `db.query("SELECT * FROM invoices WHERE id=" + req.params.id)`. Finding: **SQL injection**, Critical, `invoice.js:42`, category Injection. Fix: use a parameterized query — `db.query("SELECT * FROM invoices WHERE id=?", [req.params.id])`. Also note the missing ownership check (IDOR) — any user can read any invoice id.2425## Pitfalls2627- **Grepping for `eval` and stopping.** Real injection hides behind wrappers and helpers; follow the data, not the keyword.28- **Reporting without a fix.** A finding with no concrete remediation gets ignored. Always include the corrected pattern.29- **Trusting framework defaults blindly.** ORMs and templates have raw-query and raw-HTML escape hatches; check whether they are used.30- **Severity inflation.** Marking everything Critical trains reviewers to ignore you. Rank honestly by impact and reachability.3132## Output format3334```35## Summary36Files reviewed: <list>. Overall risk posture: <sentence>.3738## Findings39| Severity | File:line | Category | Description | Recommended fix |40|----------|-----------|----------|-------------|-----------------|4142## Quick wins43- <low-effort, high-value fix>4445## Follow-ups46- <needs design change or owner decision>47```