Threat modeling is hypothesis generation for an adversary. Walk the change set as the attacker would: where does untrusted input enter, what trust boundary does it cross, what does it gain on the other side. Every unaudited path is a free move for the attacker.
When to Apply / NOT
Apply: new external surface (HTTP route, RPC method, file upload); AuthN/AuthZ change; deserialization / parsing of untrusted input; new dependency or major-version upgrade; cryptographic change; pre-release of public-facing service; incident postmortem.
NOT apply: internal refactor with no trust-boundary delta; pure performance work; documentation-only changes; internal-only experimental code.
Anti-patterns
- Allowlist-by-omission: treating "no obvious issue" as "secure".
- Crypto improvisation: hand-rolling primitives.
- Trust the client: validating only client-side.
- Logging secrets: tokens, PII, session cookies in logs.
- Default-permit ACL: authorization checks on opt-in basis.
- Magic-string config: secrets in source / env files.
- Outdated SBOM: stale dependency snapshots.
- Skipping the threat model: jumping to checklist without naming assets/actors/boundaries.
STRIDE Question Template
Apply each prompt to every component touched by the change.
| Letter |
Threat |
Required questions |
| S |
Spoofing |
Who is the principal? How is identity proven? Can the credential be forged, replayed, or stolen? Is MFA / mutual-auth enforced? |
| T |
Tampering |
What inputs cross the trust boundary? Are they validated against an explicit schema (Zod / Pydantic / serde)? Are messages integrity-protected (HMAC / signature / TLS)? |
| R |
Repudiation |
Are security-relevant actions logged with actor + timestamp + outcome? Are logs append-only / tamper-evident? |
| I |
Information Disclosure |
What data is returned in error paths, logs, telemetry? Are PII / secrets ever serialized? Are timing side-channels addressed (constant-time compare)? |
| D |
Denial of Service |
Are inputs bounded (size, count, depth)? Is parsing resource-limited (zip-bomb, billion-laughs, ReDoS)? Are external calls rate-limited? |
| E |
Elevation of Privilege |
What privilege does the new code execute under? Is least privilege honored? Can input alter privilege (path traversal, SQL injection, deserialization gadget)? |
For each "yes" / "unclear" answer, file a finding with severity and remediation owner.
OWASP Top 10 (2021) Walkthrough
- Broken Access Control —
git grep -n -C 3 'authorize\|@PreAuthorize\|require_role' then trace policy.
- Cryptographic Failures —
git grep -n -E 'MD5|SHA1|DES|Random\(\)' for weak primitives. Use -E (extended regex) for alternation; -F (fixed-string) breaks the pipe-as-OR. Add ecosystem patterns as needed: Math.random, secrets.choice, Mersenne constants.
- Injection —
ast-grep patterns for unparameterized queries / shell concat / template eval.
- Insecure Design — threat model walk; cross-check STRIDE.
- Security Misconfiguration — TLS / CORS / CSP / cookie flags / debug toggles.
- Vulnerable & Outdated Components — language-family CVE scanner.
- Identification & Authentication Failures — token TTL, refresh, session fixation, MFA.
- Software & Data Integrity Failures — lockfile pinned; signature-verified artifacts; CI provenance.
- Security Logging & Monitoring Failures — audit log coverage; alert on auth-fail / privilege-escalation.
- Server-Side Request Forgery — egress allowlist; SSRF guard on URL inputs.
Parallel Dep-Audit Tooling
| Family |
CVE scanner |
Secrets / history |
SBOM |
| Rust |
cargo audit, cargo deny check advisories |
gitleaks, trufflehog |
cargo cyclonedx, syft |
| Python |
pip-audit, safety check |
gitleaks, detect-secrets |
cyclonedx-py, syft |
| JavaScript/TypeScript |
npm audit, pnpm audit, bun audit |
gitleaks, trufflehog |
cyclonedx-bom, syft |
| Go |
govulncheck, nancy |
gitleaks, trufflehog |
cyclonedx-gomod, syft |
| Java/Kotlin |
OWASP Dependency-Check, gradle dependencyCheckAnalyze |
gitleaks, trufflehog |
CycloneDX Gradle/Maven, syft |
| OCaml |
opam audit, opam-repository advisory feed |
gitleaks, detect-secrets |
syft (filesystem) |
Use fd -e <ext> (not find). Use git grep -n -F 'literal' (not grep). Use bat -P -p -n (not cat).
Constitutional Rules
- Default deny.
- Validate at the trust boundary — schema-validate every input.
- Never roll your own crypto.
- No secrets in source — vault-only; enforce via
gitleaks.
- Pin and verify — lockfiles checked in, integrity hashes enforced.
- Log security events — every AuthN/AuthZ outcome.
- Severity is a contract — Critical/high block merge.
1---2name: security-review-263description: Adversarial security audit — STRIDE, OWASP Top 10, supply-chain (CVE/SBOM), secrets scan, auth/authz analysis. Use on changes touching auth, input parsing, deserialization, network I/O, dependencies, or secrets; before any production release or external-surface PR.4---5
6Threat modeling is hypothesis generation for an adversary. Walk the change set as the attacker would: where does untrusted input enter, what trust boundary does it cross, what does it gain on the other side. Every unaudited path is a free move for the attacker.
7
8## When to Apply / NOT
9
10Apply: new external surface (HTTP route, RPC method, file upload); AuthN/AuthZ change; deserialization / parsing of untrusted input; new dependency or major-version upgrade; cryptographic change; pre-release of public-facing service; incident postmortem.
11
12NOT apply: internal refactor with no trust-boundary delta; pure performance work; documentation-only changes; internal-only experimental code.
13
14## Anti-patterns
15
16- **Allowlist-by-omission**: treating "no obvious issue" as "secure".
17- **Crypto improvisation**: hand-rolling primitives.
18- **Trust the client**: validating only client-side.
19- **Logging secrets**: tokens, PII, session cookies in logs.
20- **Default-permit ACL**: authorization checks on opt-in basis.
21- **Magic-string config**: secrets in source / env files.
22- **Outdated SBOM**: stale dependency snapshots.
23- **Skipping the threat model**: jumping to checklist without naming assets/actors/boundaries.
24
25## STRIDE Question Template
26
27Apply each prompt to every component touched by the change.
28
29| Letter | Threat | Required questions |
30|---|---|---|
31| **S** | Spoofing | Who is the principal? How is identity proven? Can the credential be forged, replayed, or stolen? Is MFA / mutual-auth enforced? |
32| **T** | Tampering | What inputs cross the trust boundary? Are they validated against an explicit schema (Zod / Pydantic / serde)? Are messages integrity-protected (HMAC / signature / TLS)? |
33| **R** | Repudiation | Are security-relevant actions logged with actor + timestamp + outcome? Are logs append-only / tamper-evident? |
34| **I** | Information Disclosure | What data is returned in error paths, logs, telemetry? Are PII / secrets ever serialized? Are timing side-channels addressed (constant-time compare)? |
35| **D** | Denial of Service | Are inputs bounded (size, count, depth)? Is parsing resource-limited (zip-bomb, billion-laughs, ReDoS)? Are external calls rate-limited? |
36| **E** | Elevation of Privilege | What privilege does the new code execute under? Is least privilege honored? Can input alter privilege (path traversal, SQL injection, deserialization gadget)? |
37
38For each "yes" / "unclear" answer, file a finding with severity and remediation owner.
39
40## OWASP Top 10 (2021) Walkthrough
41
421. **Broken Access Control** — `git grep -n -C 3 'authorize\|@PreAuthorize\|require_role'` then trace policy.
432. **Cryptographic Failures** — `git grep -n -E 'MD5|SHA1|DES|Random\(\)'` for weak primitives. Use `-E` (extended regex) for alternation; `-F` (fixed-string) breaks the pipe-as-OR. Add ecosystem patterns as needed: `Math.random`, `secrets.choice`, `Mersenne` constants.
443. **Injection** — `ast-grep` patterns for unparameterized queries / shell concat / template eval.
454. **Insecure Design** — threat model walk; cross-check STRIDE.
465. **Security Misconfiguration** — TLS / CORS / CSP / cookie flags / debug toggles.
476. **Vulnerable & Outdated Components** — language-family CVE scanner.
487. **Identification & Authentication Failures** — token TTL, refresh, session fixation, MFA.
498. **Software & Data Integrity Failures** — lockfile pinned; signature-verified artifacts; CI provenance.
509. **Security Logging & Monitoring Failures** — audit log coverage; alert on auth-fail / privilege-escalation.
5110. **Server-Side Request Forgery** — egress allowlist; SSRF guard on URL inputs.
52
53## Parallel Dep-Audit Tooling
54
55| Family | CVE scanner | Secrets / history | SBOM |
56|---|---|---|---|
57| Rust | `cargo audit`, `cargo deny check advisories` | `gitleaks`, `trufflehog` | `cargo cyclonedx`, `syft` |
58| Python | `pip-audit`, `safety check` | `gitleaks`, `detect-secrets` | `cyclonedx-py`, `syft` |
59| JavaScript/TypeScript | `npm audit`, `pnpm audit`, `bun audit` | `gitleaks`, `trufflehog` | `cyclonedx-bom`, `syft` |
60| Go | `govulncheck`, `nancy` | `gitleaks`, `trufflehog` | `cyclonedx-gomod`, `syft` |
61| Java/Kotlin | OWASP Dependency-Check, `gradle dependencyCheckAnalyze` | `gitleaks`, `trufflehog` | CycloneDX Gradle/Maven, `syft` |
62| OCaml | `opam audit`, opam-repository advisory feed | `gitleaks`, `detect-secrets` | `syft` (filesystem) |
63
64Use `fd -e <ext>` (not `find`). Use `git grep -n -F 'literal'` (not `grep`). Use `bat -P -p -n` (not `cat`).
65
66## Constitutional Rules
67
681. **Default deny**.
692. **Validate at the trust boundary** — schema-validate every input.
703. **Never roll your own crypto**.
714. **No secrets in source** — vault-only; enforce via `gitleaks`.
725. **Pin and verify** — lockfiles checked in, integrity hashes enforced.
736. **Log security events** — every AuthN/AuthZ outcome.
747. **Severity is a contract** — Critical/high block merge.