Security Review¶
Find exploitable risks early, provide concrete fixes, and keep recommendations practical for engineering delivery.
Review Principles¶
- Prioritize exploitable risk over style issues.
- Ground every claim in code/config/runtime evidence.
- Distinguish confirmed vulnerabilities from hypotheses.
- Provide reproducible proof for high-risk findings.
- Map findings to standards for auditability.
- If evidence is missing, state
Not found in repo. - Fail closed: if a mandatory gate cannot be executed, state it explicitly and do not claim full coverage.
Evidence Confidence (Mandatory)¶
Each finding must include one confidence label:
confirmed: vulnerable path proven by code and/or reproducible execution.likely: strong evidence with one missing runtime assumption.suspected: weak evidence requiring additional data.
Do not report P0/P1 without confirmed or explicit justification.
False-Positive Suppression Rules¶
Before publishing a finding, check suppression conditions:
- Existing upstream guard already blocks the path.
- Input is not attacker-controlled at trust boundary.
- Sink is parameterized/safely encoded by framework guarantees.
- Environment-only theoretical risk without reachable path.
If suppressed:
- keep a short note under
Open questions / assumptions - mark as
suppressed(not a finding) - explain blocking control and residual risk
Severity Model¶
P0 Critical: immediate compromise (RCE, auth bypass, key exfiltration, payment tampering).P1 High: strong exploit path (injection, IDOR, sensitive data leak, broken authz).P2 Medium: meaningful defense gap likely to become exploitable.P3 Low: hardening improvement.
Remediation SLA (Default)¶
Use this unless the team provides stricter policy:
P0: mitigation immediately, full fix within 24h.P1: fix within 3 business days.P2: fix within 14 calendar days.P3: backlog with planned milestone.
If SLA differs, state the project policy explicitly.
Baseline Diff Mode (Mandatory When Baseline Exists)¶
When previous review artifacts exist, compare current findings with baseline and output:
new: not present in baselineregressed: existed before and severity/confidence worsenedunchanged: still present without material changeresolved: removed since baseline
If no baseline exists, state Baseline not found.
Review Depth Selection (Mandatory First Step)¶
Before starting, classify review depth based on change scope:
| Signal | Depth | Process |
|---|---|---|
| Changed files ≤ 3 AND no trust-boundary / auth / crypto / payment paths touched | Lite | Steps 1-4, Gate A, Gate D (triage only), suppression filter, findings, Gate F |
| Changed files 4-15 OR any security-sensitive path touched | Standard | Full 15-step process |
| Changed files > 15 OR new service / new external integration / auth redesign | Deep | Full 15-step process + extended call-graph tracing beyond immediate callers |
Trigger signals that force Standard or Deep regardless of file count:
- Auth/authz middleware or handler changes
- Crypto, TLS, or secret-management code changes
- Payment/financial transaction paths
- New HTTP/gRPC endpoints exposed
- Dockerfile, K8s manifest, or CI pipeline security config changes
go.mod/go.sumdependency changes- Any file under
internal/auth/,internal/crypto/,pkg/security/, or equivalent
When Lite is selected, record: Review depth: Lite (N files changed, no security-sensitive paths). Gates B/C/E skipped per scope policy.
Fast Pass (Lite Only)¶
If ALL conditions are met during Lite triage:
- All 10 Gate D domains classify as N/A
- All 11 scenario checklists classify as N/A
- Secret pattern sweep is clean
- No constructor/acquisition calls found in Gate A
Then output a condensed report instead of the full Output Contract:
- Review depth + rationale (mandatory)
Fast Pass: all domains N/A, all scenarios N/A, no findings.- JSON summary with
pass: trueand zero counts (mandatory) - Gate F uncovered risk list (mandatory, may be empty)
This avoids verbose N/A tables for truly benign changes while preserving audit traceability.
Fixed Process + Mandatory Gates¶
The following process is mandatory for Standard and Deep reviews. Lite reviews follow the subset noted above.
- Scope the change and select review depth.
- Map trust boundaries.
- Run scenario checks.
- Run focused automation checks.
- Run
Gate A: constructor-release pairing audit. - Run
Gate B: Go resource inventory scan. - Run
Gate C: third-party lifecycle contract verification. - Run
Gate D: Go secure-coding 10-domain coverage (for Go repos). - Verify exploitability.
- Run
Gate E: second-pass falsification review. - Apply suppression filter.
- Compare with baseline (if available).
- Report findings first.
- Provide remediation plan and risk acceptance entries.
- Provide
Gate F: uncovered risk list.
If any mandatory gate cannot be executed, record it under Uncovered Risk List and downgrade confidence where applicable.
Applicability-First Execution (Mandatory)¶
To control review cost and avoid unnecessary depth, execute in two phases:
Phase 1 (triage): classify each Go domain asApplicableorN/Afrom changed files + adjacent call paths.Phase 2 (deep review): run detailed checks and domain-specific tooling only forApplicabledomains.
Rules:
N/Ais allowed only with a one-line reason tied to code evidence.- Do not mark
N/Aif there is any trigger signal (relevant imports, touched config, related middleware, DB/crypto/TLS paths, dependency changes). - Domain-specific reproducer/tests are required only for
Applicabledomains with findings.
N/A Judgment Examples¶
| Domain | Scenario | Verdict | Rationale |
|---|---|---|---|
| Randomness safety | Change adds a new CLI --dry-run flag; no token/session/nonce code touched | N/A | No import of math/rand or crypto/rand in changed files or callers |
| Injection + SQL | Change updates a Markdown documentation file only | N/A | No .go files changed; no SQL/exec/template paths reachable |
| TLS safety | Change modifies HTTP handler logic but no TLS config, http.Client, or dial code touched | N/A | No tls.Config, InsecureSkipVerify, or custom transport in changed scope |
| Concurrency safety | Change adds a pure function with no shared state, goroutines, or channels | N/A | Function is stateless; no go keyword, sync.*, or channel ops in diff |
| Container security | No Dockerfile, K8s manifests, or CI pipeline files in changed scope | N/A | git diff --name-only shows no infra/deploy files |
Anti-pattern: marking a domain N/A when imports or adjacent call paths contain trigger signals (e.g., database/sql imported → Domain 2 must be Applicable).
Mandatory Gate Definitions¶
Gate A: Constructor-Release Pairing (Mandatory)¶
For changed code and immediately related call paths, enumerate and verify pairings for every constructor/acquisition call:
- Constructors/acquisition:
New*,Open*,Acquire*,Begin*,Dial*,Listen*,Create*,WithCancel/WithTimeout/WithDeadline. - Required pairings:
Close,Release,Rollback/Commit,Stop,Cancel, or explicit ownership transfer documented in code.
Output requirement:
- Include a short pairing table in analysis notes.
- Any missing or ambiguous pairing is at least
P2unless proven harmless.
Gate B: Go Resource Inventory (Mandatory for Go)¶
Scan all changed code for resource acquisition without matching release. Covers: rows, stmt, tx, conn, file, http.Response.Body, net.Listener, driver objects, goroutine, context cancel, io.Pipe.
Key checks: closed on both success and error paths; no defer inside loops; goroutines have bounded lifecycle; WithTimeout paired with defer cancel().
Reference: See
references/go-secure-coding.md§ Gate B for the full resource inventory table and anti-patterns.
Gate C: Third-Party Lifecycle Contract Verification (Mandatory)¶
When code uses driver/framework objects with non-obvious lifecycle rules (for example godror, sql extensions, SDK clients):
- Verify lifecycle requirements from primary sources (library source code and/or official docs).
- Cite exactly what contract was used for the decision.
- If no contract can be verified, mark confidence at most
suspectedand list underUncovered Risk List.
Gate D: Go Secure-Coding 10-Domain Coverage (Mandatory for Go)¶
For Go repositories, score coverage for these 10 domains:
- Randomness safety —
crypto/randfor secrets;math/randOK for non-security use. - Injection + SQL lifecycle — parameterized SQL,
ORDER BYallowlist,rows.Close/Err,Commit/Rollback. - Sensitive data handling — mask logs, opaque error messages, response DTO minimization.
- Secret/config management — no hardcoded secrets, env fail-fast,
nolint:gosecwith rationale. - TLS safety —
MinVersion >= TLS1.2, noInsecureSkipVerifyin production. - Crypto primitives — bcrypt/argon2id for passwords, AEAD for encryption,
subtle.ConstantTimeCompare. - Concurrency safety —
go test -raceclean, no TOCTOU in auth/balance, no unsynchronized map access. - Go injection sinks —
html/templatenottext/template,exec.Commandarg separation,filepath.Jointraversal. - Static scanner posture —
gosectriaged, suppressednolinthas rationale. - Dependency posture —
govulnchecksource-mode reachability.
Execution: D1 triage (Applicable/N/A) → D2 deep review on applicable domains only.
Output: each domain PASS/FAIL/N/A with one-line evidence. Any FAIL with exploitable path becomes a finding.
Reference: See
references/go-secure-coding.md§ Gate D for detailed checks, code examples, and decision tables per domain.
Gate E: Second-Pass Falsification Review (Mandatory)¶
After first-pass findings, run a dedicated second pass to disprove your own conclusion:
- Ask: "What critical issue would I have missed if first pass over-focused on exploitability class X?"
- Focus on availability, consistency, lifecycle, and partial-failure paths.
- Specifically re-check: transaction boundaries, rollback guarantees, cleanup on error/panic, idempotency race windows.
Output requirement:
- Add a one-line summary in report:
Second-pass falsification completed: yes/no.
Gate F: Uncovered Risk List (Mandatory)¶
Always output unresolved coverage gaps to avoid false completeness.
Each item must include:
- Area not covered
- Why not covered (tool/env/access/time)
- Security impact if the gap hides a defect
- Recommended follow-up action and owner suggestion
Anti-Examples (Common Review Mistakes)¶
These are structured examples of review mistakes this skill is designed to prevent. Each shows a wrong approach and the correct alternative.
AE-1: Style Finding Reported as Security Issue¶
Wrong: Reporting P3 — function has 200 lines, hard to review for security as a security finding. Correct: Code complexity is a code quality issue. Only report security findings when there is an exploitable or defense-gap path. If complexity obscures a real vulnerability, report the vulnerability itself with evidence.
AE-3: Over-Reporting False Positives¶
Wrong: P1 — math/rand used in pkg/display/shuffle.go:12 for randomizing quiz question order without checking if the output is security-relevant. Correct: Suppressed — math/rand usage is for display ordering of quiz questions; output is not attacker-exploitable and does not protect a security boundary (Suppression Rule 2).
AE-5: Missing Gate Reported as Full Coverage¶
Wrong: Report says "all gates passed" but go test -race was not run because test suite was unavailable. Correct: Record under Uncovered Risk List: "Gate D7 (Concurrency safety) — go test -race not executed because test suite has build errors. Impact: data races may exist undetected in changed packages. Recommended: fix test build and re-run."
For additional anti-examples (N/A without evidence, confirmed without reproducer, P0 acceptance without escalation, ignoring transitive call paths), see
references/anti-examples.md.
Scenario Checklists¶
Run applicable scenarios from the full 11-scenario checklist:
- Authentication / Authorization — auth on routes, authz before ops, IDOR, token lifecycle.
- Input Validation / Injection / Uploads — schema rules, parameterized SQL, path traversal, upload controls, Go injection sinks.
- Session / JWT / Cookie / CSRF — JWT validation,
alg=nonerejection, cookie flags, CSRF. - New Endpoints and Error Surface — authn/authz strategy, error leakage, CORS, idempotency, Go-specific (
MaxBytesReader, timeouts). - Secrets / Crypto / Key Management — no hardcoded secrets, env-only loading, bcrypt/argon2id, constant-time compare.
- Payment / Financial Transitions — server-side validation, replay protection, transaction boundaries, balance concurrency.
- Sensitive Data Storage / Transmission — TLS, field masking, encryption-at-rest, response minimization.
- Third-Party Integrations — timeout/retry bounds, signature verification, SSRF-safe URL, fail-safe behavior.
- Supply Chain / Dependency / Build Path —
govulncheck,gosec, dependency pinning. - Container / Deployment Security — Dockerfile non-root, image pinning, K8s securityContext, NetworkPolicy, CI secret store.
- Concurrency Safety as Security Risk — TOCTOU, double-spend race, concurrent map crash,
go test -race.
Reference: See
references/scenario-checklists.mdfor the full checklist with per-item details and Go-specific subsections.
Focused Automation Gate¶
Run when tools are available; never claim results without running commands.
Execution policy:
- Always run low-cost baseline sweep (
rgsecrets patterns). - Run expensive scanners according to
Gate Dapplicability: - If dependency/module graph changed or third-party risk is
Applicable, rungovulncheck. - If security-sensitive Go code changed, run
gosecon affected scope (or full repo when scope is unclear). - If a scanner is skipped because the domain is
N/A, record that explicitly inAutomation Evidence.
# secret pattern sweep
rg -n "(AKIA[0-9A-Z]{16}|-----BEGIN (RSA|EC|OPENSSH|PRIVATE) KEY-----|ghp_[A-Za-z0-9]{36}|xox[baprs]-|AIza[0-9A-Za-z\-_]{35}|password\s*=|secret\s*=|token\s*=)" .
# Go race detector on changed packages (mandatory for Standard/Deep if tests exist)
go test -race -count=1 ./path/to/changed/...
# Go security scanners
gosec ./...
govulncheck ./...
# Optional cross-check: module exposure view (may include unreachable vulns)
govulncheck -mode=binary ./...
Tool Interpretation Rules (Mandatory)¶
go test -race: any race detected is at leastP2; races on auth/balance/permission state areP1(CWE-367). Report goroutine stacks from race output.gosec: report rule ID, location, and whether finding is exploitable on reachable paths.govulnchecksource mode: call-trace reachable vulns are high confidence (confirmed/likely).govulncheck -mode=binary: treat as exposure signal only; do not markconfirmedwithout source reachability or equivalent proof.- Any suppressed
nolint:gosecrequires explicit rationale review; missing rationale is at leastP3hardening gap.
Language/Framework Extension Hooks¶
Default checklist targets Go services. For non-Go stacks, replace Go-specific Gate D domains with the stack-specific reference. All other gates, scenario checklists, severity model, and output contract remain unchanged. If mixed stack, split findings by module.
| Stack | Reference | Key Domains |
|---|---|---|
| Node.js / TypeScript | references/lang-nodejs.md | injection, prototype pollution, ReDoS, SSRF, middleware order |
| Java / Spring | references/lang-java.md | deserialization, SpEL/SQL injection, auth annotations, config secrets |
| Python / FastAPI / Django | references/lang-python.md | eval/pickle, SSTI, ORM safety, async blocking, dependency audit |
Standards Mapping (Mandatory)¶
Include mapping for each finding when applicable:
CWE-xxxOWASP ASVS <section>
If unclear, use Mapping: TBD with reason.
Output Contract¶
Return outputs in this order. Fields are graded MUST / SHOULD / MAY per review depth:
| # | Section | Lite | Standard | Deep |
|---|---|---|---|---|
| 1 | Findings (P0 → P3) | MUST | MUST | MUST |
| 2 | Go 10-Domain Coverage | MUST (triage only) | MUST (full) | MUST (full) |
| 3 | Automation Evidence | MUST (secret sweep only) | MUST | MUST |
| 4 | Open questions / assumptions | MAY | MUST | MUST |
| 5 | Risk Acceptance Register | MAY | MUST | MUST |
| 6 | Remediation Plan | MAY | MUST | MUST |
| 7 | Machine-Readable Summary (JSON) | MUST | MUST | MUST |
| 8 | Hardening suggestions | MAY | SHOULD | MUST |
| 9 | Uncovered Risk List | MUST | MUST | MUST |
1) Findings (P0 -> P3)¶
Each finding includes:
- Title
- Severity
- Confidence (
confirmed/likely/suspected) - Mapping (
CWE/OWASP ASVS) - File/line
- Exploit path
- Impact
- Minimal reproducer (required for confirmed P0/P1)
- Recommended fix
- Suggested regression/negative test
- Baseline status (
new/regressed/unchanged)
One-Shot Finding Example¶
SEC-001: IDOR — Any authenticated user can access other users' orders
- Severity: P1 High
- Confidence: confirmed
- Mapping: CWE-639 (Authorization Bypass Through User-Controlled Key) / OWASP ASVS V4.1.2
- File/line:
internal/handler/order.go:47- Exploit path:
GET /api/orders/:idextractsidfrom URL path and passes it directly torepo.GetOrder(id)without verifyingorder.UserID == ctx.UserID(). Any authenticated user can read any order by iterating IDs.- Impact: Full horizontal privilege escalation on order data (PII, payment amounts, addresses).
- Reproducer:
- Recommended fix: Return 404 (not 403) to avoid confirming the order exists.
- Regression test: Add
TestGetOrder_CrossUser_Returns404— create order as User A, request as User B, assert 404.- Baseline status: new
2) Go 10-Domain Coverage (Required for Go repos)¶
- Domains 1..10 with
PASS/FAIL/N/A - Applicability per domain (
ApplicableorN/Awith reason) - One-line evidence per domain (deep evidence required only for
Applicabledomains) - Total
PASScount and key failed domains
3) Automation Evidence¶
- Command list actually executed
- Key outputs (short)
- Tools skipped/unavailable and reason (including
N/Aapplicability skips)
4) Open questions / assumptions¶
5) Risk Acceptance Register¶
P0 findings MUST NOT be accepted without VP-level or equivalent sign-off; record the approver explicitly. P1 findings require tech-lead-level sign-off.
For each accepted risk entry:
- Finding ID
- Reason for acceptance
- Compensating controls
- Approver (name and role)
- Owner
- Expiry/review date
6) Remediation Plan¶
- Immediate
- Short-term
- Backlog
7) Machine-Readable Summary (JSON)¶
Also output a compact JSON block for CI/inbox ingestion:
{
"summary": {
"pass": false,
"score": "10/14",
"baseline": "present"
},
"counts": {
"p0": 0,
"p1": 1,
"p2": 2,
"p3": 1
},
"changes": {
"new": 2,
"regressed": 1,
"unchanged": 1,
"resolved": 0
},
"go_domains": {
"required": true,
"total": 10,
"pass": 7,
"fail": 2,
"na": 1
},
"findings": [
{
"id": "SEC-001",
"severity": "P1",
"confidence": "confirmed",
"status": "new",
"cwe": "CWE-639",
"asvs": "V4",
"file": "internal/handler/account.go:88"
}
]
}
8) Hardening suggestions¶
9) Uncovered Risk List (Mandatory)¶
Load References Selectively¶
Read only the references needed for the current review. The review depth and language determine what to load.
| Condition | Load files | Typical tokens |
|---|---|---|
| Go code, Standard/Deep | references/go-secure-coding.md + references/scenario-checklists.md | ~5,800 |
| Go code, Lite | references/scenario-checklists.md only | ~1,200 |
| Node.js / TypeScript | references/lang-nodejs.md + references/scenario-checklists.md | ~2,200 |
| Java / Spring | references/lang-java.md + references/scenario-checklists.md | ~2,100 |
| Python / FastAPI / Django | references/lang-python.md + references/scenario-checklists.md | ~2,000 |
| General / multi-language | references/scenario-checklists.md only | ~1,200 |
| Severity calibration needed | references/severity-calibration.md | ~600 |
| Additional anti-examples | references/anti-examples.md | ~400 |
Lite reviews must NOT load go-secure-coding.md — Gate B/C/E are skipped and domain triage uses only SKILL.md definitions.
Bundled Assets¶
| File | Purpose |
|---|---|
references/go-secure-coding.md | Gate B resource inventory + Gate D 10-domain deep reference (Go only, Standard/Deep) |
references/scenario-checklists.md | Full 11-scenario checklist with per-item details |
references/severity-calibration.md | Severity + confidence calibration rules and common finding patterns |
references/anti-examples.md | Extended anti-examples (AE-2, AE-4, AE-6, AE-7) |
references/security-review.md | General security review methodology |
references/lang-nodejs.md | Node.js/TypeScript domain-specific gates |
references/lang-java.md | Java/Spring domain-specific gates |
references/lang-python.md | Python/FastAPI/Django domain-specific gates |