From code-audit-rigor
Use when conducting high-stakes code audits where intuition alone is insufficient — security-critical reviews, financial / cryptographic / safety-critical code, or any deep dive triggered by user keywords like "rigorous review" / "deep audit" / "quantified decision" / "security review" / "對抗式 review" / "嚴謹審查". Provides five core review-discipline principles, four quantitative frameworks (Expected-Value decision threshold, score-based calibration, STRIDE+CWE classification, mandatory cross-reference contract with quoted-code anchoring), plus three engineering guarantees adapted from alibaba/open-code-review (path-matched language rule packs with suppression lists, deterministic scope/coverage checklist, reference-anchoring verification). This skill is fully self-contained — it does not depend on the host project's CLAUDE.md to function. SKIP for routine PR review or simple bug fixes where standard review flows are adequate. Inspired by adversarial multi-agent review patterns (e.g. codexstar69/bug-hunter) and alibaba/open-code-review's deterministic-engineering layer, distilled into Claude-native checkpoints without auto-fix or LLM-readable injection vectors.
How this skill is triggered — by the user, by Claude, or both
Slash command
/code-audit-rigor:code-audit-rigorThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> **Activation reminder (for Claude):** if you are reading this file, the user has signalled this is not a routine review — they want quantitative discipline applied to a high-stakes decision. Do NOT short-cut to "looks fine to me" or "probably safe." Apply the principles and frameworks in order, document each step, and surface uncertainty to the user rather than absorb it as confidence.
Activation reminder (for Claude): if you are reading this file, the user has signalled this is not a routine review — they want quantitative discipline applied to a high-stakes decision. Do NOT short-cut to "looks fine to me" or "probably safe." Apply the principles and frameworks in order, document each step, and surface uncertainty to the user rather than absorb it as confidence.
Routine code review flows are calibrated for everyday PR work. They produce findings, prioritize them, and rely on the reviewer's judgment for the final accept / reject call. That works most of the time.
But some reviews need more rigor:
For these cases, a misjudged false negative is structurally more expensive than a false positive. This skill provides the discipline and arithmetic to surface that asymmetry explicitly.
Trigger on any of:
If the user is asking for routine PR review, this skill does NOT apply.
These principles apply to every step of an audit. They are mandatory checkpoints — skipping any of them invalidates the audit.
Do a literal pass through every file in scope BEFORE forming any opinion or producing any finding. No shortcuts via:
If you have not read a file, you cannot have a finding about it.
Before submitting any finding, ask yourself this question literally. If the honest answer is "guessing from memory" or "inferring from the diff", re-read the relevant file:lines now.
LLMs reconstruct plausible-sounding code from training data. This self-check is the single most effective counter-measure.
Diff-only review is unreliable because:
User, user, userObj, userData) may refer to different types or scopesFor any critical or high-severity claim, you MUST grep for the symbol and Read the full definition before adopting the finding.
Tool selection note: when the project has a .codegraph/ index, prefer codegraph for structural queries — codegraph_callers for call-chain tracing, codegraph_impact for blast radius, codegraph_explore for unfamiliar architecture — because grep misses dynamic-dispatch call sites (callbacks, DI containers, event handlers). Grep remains the correct tool for literal-text work: the Phase 4 quoted-code anchoring check is verbatim string matching, not a structural query — keep using Grep there.
If three independent agents (or three review tools, or three reviewers) all flag the same issue, that is not evidence the issue is real. They are reading the same diff through similar reasoning paths — misreads amplify in the same direction, not orthogonally.
Treat any agent-reported confidence score as "the agent's confidence in its own reasoning", not as "probability the bug is real". Always re-verify against source code yourself.
When deciding whether to dismiss a finding as a false positive, treat the cost of dismissing a real bug as 2× the severity score (see Framework 1 below). This asymmetric penalty exists because:
This penalty is the engine that makes the EV math (Framework 2) work.
Incentive structure to align findings with severity, penalize false positives:
| Severity | Confirmed bug | False positive |
|---|---|---|
| Critical (auth bypass, RCE, data leak) | +10 | −3 |
| High (injection, privilege escalation) | +5 | −3 |
| Medium (logic error, missing validation) | +3 | −3 |
| Low (style, minor inefficiency) | +1 | −3 |
Rule: Five real bugs beat twenty false positives. If finding count starts to balloon, re-read the code before adding more — quality > quantity.
Before dismissing or acting on any finding, compute its expected value:
EV = (confidence%) × points − (100 − confidence%) × 2 × points
confidence% = honest estimate that the finding represents a real bug (0–100)points = severity score from Framework 12× factor encodes Principle 5Decision rule:
EV > 0 → finding is worth investigating / acting onEV < 0 → safe to dismiss, but record the rationale so it can be challengedWorked examples:
EV = 0.5 × 10 − 0.5 × 2 × 10 = −5. Dismiss is statistically supported, BUT 50% confidence on a critical finding usually means insufficient investigation — re-read to push confidence above 67% or below 33% before deciding.EV = 0.8 × 3 − 0.2 × 2 × 3 = +1.2. Investigate / act.EV = 0.6 × 1 − 0.4 × 2 × 1 = −0.2. Dismiss with note.Anti-pattern: Using "I'm not sure" as a default to skip findings. The EV formula forces an explicit confidence number — that is the point.
Every security finding MUST be tagged with both:
STRIDE category (one of):
| Code | Name | Example |
|---|---|---|
| S | Spoofing | Forged identity, JWT signature bypass |
| T | Tampering | Modified data in transit / at rest, parameter pollution |
| R | Repudiation | Missing audit logs, log injection |
| I | Information disclosure | Stack traces in prod, PII in logs, side-channel leaks |
| D | Denial of service | Unbounded loops, memory bombs, ReDoS |
| E | Elevation of privilege | Auth bypass, role escalation, sandbox escape |
CWE ID — pick the most specific applicable ID at https://cwe.mitre.org/
Common CWEs to memorize:
| CWE | Description |
|---|---|
| CWE-22 | Path Traversal |
| CWE-78 | OS Command Injection |
| CWE-79 | Cross-site Scripting (XSS) |
| CWE-89 | SQL Injection |
| CWE-200 | Information Exposure |
| CWE-287 | Improper Authentication |
| CWE-352 | Cross-Site Request Forgery (CSRF) |
| CWE-434 | Unrestricted Upload of Dangerous File |
| CWE-502 | Deserialization of Untrusted Data |
| CWE-639 | Insecure Direct Object Reference (IDOR) |
| CWE-732 | Incorrect Permission Assignment |
| CWE-798 | Hardcoded Credentials |
| CWE-862 | Missing Authorization |
| CWE-863 | Incorrect Authorization |
| CWE-918 | Server-Side Request Forgery (SSRF) |
| CWE-1333 | Inefficient Regex (ReDoS) |
If you cannot pick a CWE, the finding is probably too vague — refine it until you can.
Worked example:
user.isAdmin after fetching user object, but the fetcher uses cached results that may include stale role data"Every finding output MUST include a crossReferences array citing specific file:line evidence plus a verbatim quotedCode anchor. Empty array is rejected. A crossReference without quotedCode is rejected.
Required schema for each finding:
{
"id": "BUG-001",
"title": "Short imperative description",
"severity": "Critical | High | Medium | Low",
"confidence": 0-100,
"stride": "S | T | R | I | D | E",
"cwe": "CWE-NNN",
"claim": "What is wrong, in one sentence",
"evidence": "Why I believe it is wrong, in 1-3 sentences",
"crossReferences": [
{"file": "src/auth/middleware.ts", "lines": "42-58", "quotedCode": "if (user.isAdmin) {", "note": "isAdmin check after stale fetch"},
{"file": "src/auth/cache.ts", "lines": "15-30", "quotedCode": "const ROLE_TTL = 30 * 60", "note": "TTL 30 min, role changes immediate"}
],
"ev": 8.0,
"decision": "ACT | DISMISS | INVESTIGATE_FURTHER"
}
The stride and cwe fields are required for security findings, optional otherwise.
quotedCode rules (adapted from alibaba/open-code-review's external re-location module):
+, -, ) if quoting from a diffquotedCode exists so the reference can be mechanically verified (Phase 4 anchoring check below). A reference whose quote cannot be found in the file is the signature of an LLM reconstructing plausible code from memory — exactly the failure mode this contract exists to catch.
Self-check before submitting any finding:
"Have I actually read every file:line in
crossReferences, or am I guessing?" If the answer is "guessing", re-read the files now (Principle 2).
Set the file list explicitly before starting. The in-scope file list MUST come from a mechanical source — never reconstructed from memory or inferred from the conversation:
git diff --name-only <base>...HEAD (plus git diff --name-only HEAD for working-tree changes)git show --name-only <sha>Glob over the stated directories, or an explicit user-provided listRecord which command produced the list — it becomes the coverage checklist that Phase 5 must reconcile against, file by file. State which files are in scope, which are explicitly excluded and why. Output:
SCOPE:
source: git diff --name-only origin/main...HEAD
in: src/auth/**, src/api/auth-routes.ts
out: tests/**, docs/**, third-party/**
reason for exclusions: <one line>
For each in-scope file, resolve the applicable review rule pack. Resolution walks three layers in priority order — first layer that matches wins for that file:
<repo>/.reviewrules/manifest.json (team-shared, committed to git), if it exists~/.claude/review-rules/manifest.json (personal preferences), if it existsrules/manifest.json shipped with this plugin, located at <plugin-root>/rules/ (two directories above this SKILL.md: ../../rules/manifest.json relative to this file)Each manifest maps glob patterns to rule docs; within a layer, entries are evaluated top-to-bottom and the first matching pattern wins (patterns support ** and {a,b} expansion). Read the matched rule docs — each contains a Review focus section (what to hunt for in this file type) and a Do NOT report suppression list (known false-positive classes for this file type).
When resolving rule packs or expanding an audit sweep to a new category, read tools/sweep-patterns.md for targeted grep patterns by category (auth, injection, secrets, deserialization, concurrency, IaC, LLM prompt injection) with false-positive cautions.
Output a short resolution table so the user can audit which rules were applied:
RULES:
src/auth/middleware.ts → ts_js_tsx_jsx.md (built-in)
config/deploy.yml → yaml_iac.md (built-in)
app/Models/Order.php → .reviewrules/laravel-payment.md (project)
This layering is adapted from alibaba/open-code-review's four-tier priority chain. The suppression lists are scoped per file type and reviewed content — they are NOT the global "settled false-positive class" hard-exclusions this skill deliberately rejects (see Inspiration section): a suppression entry only ever lowers priority for a named, file-type-specific pattern, and Phase 4 steel-manning still applies to everything.
Read every in-scope file end to end. Take notes on:
Do not produce findings yet.
For each candidate issue:
claim and evidence in plain languagecrossReferences with quotedCode anchors (Framework 4)tools/triage-decision-tree.md when there is a conflict between EV, severity label, confidence, and statusdecision fieldStep 1 — Reference anchoring check (mechanical). For each finding marked ACT or INVESTIGATE_FURTHER, verify every crossReference with Grep before any reasoning:
Grep the quotedCode (or its most distinctive substring) in the claimed filelines range (±10 lines) → anchored; proceedlines field to the actual location, re-check that the claim still holds at the real locationUNVERIFIED_REFERENCE, reduce confidence by 30 points, and recompute EV — this usually drops it below the 67% threshold, which is the intended outcome for memory-reconstructed referencesThis is the deterministic counterpart to Principle 2: the self-check catches guessing you notice; the grep catches guessing you don't. (Adapted from alibaba/open-code-review's external positioning module: resolve mechanically first, fall back to re-location, never trust unanchored line numbers.)
Step 2 — Steel-man the opposite (read STEEL_MANNING.md). For each finding that survives anchoring, execute the structured steel-manning procedure defined in STEEL_MANNING.md (located at skills/code-audit-rigor/STEEL_MANNING.md relative to the plugin root, or ./STEEL_MANNING.md relative to this file):
STEEL_MANNING.md if you have not already done so in this sessionSTEEL_MANNING.mdverified, corrected, rejected, or needs_user_decision)If steel-manning cannot be performed for a finding (e.g. insufficient code access), mark the finding needs_user_decision or INVESTIGATE_FURTHER with an explicit steel-manning: NOT_PERFORMED — <reason> note. A finding that cannot be steel-manned cannot be confirmed.
If steel-manning lowers confidence below 67% (the EV breakeven point), downgrade to INVESTIGATE_FURTHER or DISMISS; use the EV calculation in STEEL_MANNING.md as the source of truth.
Output structure:
EXECUTIVE SUMMARY: <1 paragraph>
CONFIRMED FINDINGS (sorted by EV descending):
- [Critical, conf 85, EV +6.5] BUG-001: ...
steel-manning: verified (all OC checks passed, no strong counter-evidence)
- [High, conf 72, EV +1.0] BUG-002: ...
steel-manning: corrected (OC-3 refined scope; original description overstated)
DISMISSED FINDINGS (with rationale):
- [Med, conf 30, EV -1.8] BUG-D01: dismissed because <reason>
steel-manning: rejected (OC-2: framework parameterization covers this; EV -3.2)
COVERAGE (reconciled against the Phase 1 mechanical list):
- scope source: <the command from Phase 1, e.g. git diff --name-only origin/main...HEAD>
- Read in full: <list of files>
- Skipped: <list, each with reason>
- Unaccounted: <files from the mechanical list in neither column — MUST be empty; if not, the audit is incomplete and you must go back and read them>
- Total score: <sum of confirmed point values>
The coverage section is a checklist reconciliation, not a recollection: every file in the Phase 1 mechanical list must appear in exactly one of Read / Skipped. A file you cannot place means you lost track of it — that is a structural coverage gap (the exact failure alibaba/open-code-review's deterministic file selection exists to prevent), not a formatting issue.
Always save the report to disk — output to a file path the user can refer to later (e.g. knowledge/audits/<target>-<YYYY-MM-DD>.md, audits/<target>-<YYYY-MM-DD>.md, or wherever fits the project structure). Never produce only chat output for an audit — the user instruction 產生文件或參考資料時,一律存檔到磁碟 (save artifacts to disk by default) applies here even more strictly because audit reports have value to future reviewers, not just the current session.
A clean audit is a valuable result, not a non-event. When all candidates were dismissed (typically after Phase 4 corrective steel-manning), you MUST still produce the full report. Do NOT short-cut to "looks fine, no findings." The report serves three concrete purposes:
source $ENV_FILE risk?")Required structure when zero confirmed:
The total file length of a zero-findings report is typically not shorter than a findings-present report — it should be longer if anything, because steel-manning rationales are the substance.
This skill distills the quantitative review patterns from codexstar69/bug-hunter (Hunter / Skeptic / Referee adversarial flow) into Claude-native checkpoints, plus three engineering guarantees from alibaba/open-code-review's deterministic-engineering layer (Apache-2.0):
rule_docsDeliberately NOT included:
rules/ docs are part of this plugin's reviewed, versioned content (same trust domain as SKILL.md); project-level .reviewrules/ is user-controlled and team-reviewed by definition. Treat rule docs from an unfamiliar repo with the same suspicion as any repo contentnpx claudepluginhub chinlung/claude-dev-workflow --plugin code-audit-rigorCreates, edits, and verifies skills using a test-driven development approach with pressure scenarios and subagents.