BXUP Track progress & test yourself — free
Software Engineering · Playbook · Core · ~4 min read
SOFTWARE ENGINEERING · PLAYBOOK · CORE

Security-Focused AI Review Pass: Checklist-Driven, Exploitability-Triaged

A general "review this for security" prompt produces vague hand-wringing. A checklist-driven pass — OWASP/CWE categories mapped to your diff's actual attack surface, findings triaged by exploitability — produces pre-merge catches like the ones Meta reports from their AI review tooling.

Tier: Core · Workflow area: Code Review

The AI is a tireless checklist executor; you remain the judge of exploitability, because that judgment requires knowing your deployment context.

When to use

  • Diffs touching classic attack surface: auth/session logic, input parsing, file handling, SQL/query construction, deserialization, crypto, URL fetching, subprocess/exec, permissions checks.
  • AI-generated code headed for production — models reproduce insecure idioms from training data (string-built SQL, verify=False, weak randomness for tokens) at meaningful rates.
  • Before a release when no security engineer is available for a dedicated review.

This pass supplements, never replaces, your SAST tooling and (for high-risk changes) a human security review.

Prerequisites

  • The diff plus enough surrounding context for data-flow questions (the full functions being changed, not just hunks).
  • Semgrep (free Community Edition) or your existing SAST in CI — deterministic rules first, LLM judgment second.
  • A one-paragraph deployment context you can paste: internet-facing or internal, authn/authz model, what data classes flow through (PII? payments?), sandboxing.

The workflow

  1. Run deterministic tools first.

    semgrep scan --config auto --json > /tmp/semgrep.json
    

    Anything a rule catches deterministically should never spend LLM tokens or your review attention as a "discovery" — the LLM pass is for what rules cannot see: logic-level and context-dependent flaws.

  2. Run the checklist pass with attack-surface mapping.

    You are performing a security review of this diff. Deployment context:
    [internet-facing API, JWT auth, handles PII, runs in k8s, Postgres].
    
    Step 1 — Map: list which OWASP Top 10 / CWE categories this diff plausibly
    touches, citing the specific lines that create the surface (e.g., "builds
    SQL at line 42 → injection/CWE-89"). Say NONE for untouched categories.
    
    Step 2 — For each mapped category, examine the diff and report findings:
    - finding, file:line, CWE id
    - a concrete attack input or scenario (not "an attacker could...")
    - what the code would have to look like to be safe
    
    Step 3 — Separately check these AI-codegen classics: string-concatenated
    queries/commands, disabled TLS verification, secrets or tokens in code,
    `random` used for security purposes, missing authz check on new endpoints,
    path traversal in file handling, unbounded deserialization.
    
    Do not report theoretical issues in unchanged code. Do not pad: if a
    category is clean, say clean.
    

    Requiring a concrete attack input per finding is the anti-vagueness lever — a finding without an input is a feeling.

  3. Triage by exploitability, not by CWE severity tables. For each finding, answer three questions the model cannot fully answer for you: Is the input attacker-reachable in our deployment? What is the blast radius given our data and privileges? Are there compensating controls (WAF, gateway authn, network policy)? Sort into: fix-before-merge / fix-this-sprint / accepted-with-note. Write one line of reasoning per accepted finding — that line is your future audit trail.

  4. Verify the fix breaks the attack. For each fix-before-merge item, encode the model's concrete attack scenario as a test:

    def test_report_name_is_parameterized():
        # attack input from the review finding
        resp = client.get("/reports", params={"name": "x' OR '1'='1"})
        assert resp.status_code in (200, 400)
        assert row_count("reports_audit") == audit_before  # no injection side effect
    

    A security fix without a test regresses silently the next time someone "simplifies" the code.

  5. Feed the pattern back. Every real finding becomes either a Semgrep rule (if mechanically detectable) or a line in your AI-review instructions file (pb-18). The goal is that each vulnerability class is caught one layer earlier next time.

Note

LLM security passes have real false-negative rates — a clean pass is evidence, not proof. High-risk surfaces (authn, crypto, payment flows) still get a human security review regardless of what the model says.

Tool variants

  • Copilot code review + instructions: put the step-3 AI-codegen classics into .github/copilot-instructions.md so every PR gets them automatically; run the full checklist pass manually on high-surface diffs.
  • Claude / chat with large context: best for step 2's data-flow questions across multiple files ("trace user input from handler to query").
  • Semgrep + LLM triage: pipe Semgrep JSON findings into the model to cluster duplicates, draft fix suggestions, and pre-rank — deterministic detection, LLM explanation.

Verification

  • Every mapped category cites real lines (spot-check: do the cited lines exist and create that surface?).
  • Every fix-before-merge finding has a test using the concrete attack input, failing before the fix and passing after.
  • Semgrep runs clean (or has triaged, documented exceptions) on the final diff.
  • Accepted-risk findings each carry a one-line justification tied to deployment context.

Pitfalls

  • The vague-prompt trap. "Any security issues?" yields boilerplate about validating input. The category-map + concrete-attack-input structure is what makes findings actionable.
  • Treating model severity as triage. Models rank a theoretical SSRF above a very-reachable IDOR because severity tables say so; exploitability in your topology is your call.
  • Scanning only the diff. A diff can be individually safe but complete an unsafe flow (new endpoint + old unsanitized helper). Include called functions in context for data-flow questions.
  • Hallucinated CVE/CWE citations. Models occasionally invent CVE numbers and misassign CWEs; verify identifiers before they enter tickets or client reports.

Restricted-environment variant

  • Security-sensitive code is exactly what client policies restrict most. Sanctioned order: client-tenant models (Bedrock/Azure OpenAI inside the client cloud) → Copilot Business with no-training flag → local model.
  • Semgrep CE is local and free — in fully restricted environments, expand your Semgrep ruleset to cover the step-3 classics and run the checklist as a human-driven review form; the category-map discipline works on paper.
  • Never paste real secrets, tokens, or production URLs found during review into any model — redact to SECRET_1 placeholders even in sanctioned tools; report the leak through your incident process, not a chat window.

Success criteria

  • High-surface diffs get the pass routinely, and it has caught at least one pre-merge issue a linter did not.
  • Findings arrive with concrete attack inputs and become regression tests; zero vague "improve validation" tickets.
  • Your Semgrep ruleset and review-instructions file both grow over time from real findings — the feedback loop is alive.
This is the free reading view. Open BXUP to track your progress, run the hands-on labs, and prove it with original, exam-pattern assessments.
© Anvi Innovate · BXUP — Be Exponentially Upskilled · BXUP is an independent learning platform, not affiliated with or endorsed by AWS, Microsoft, Google, NVIDIA, IBM, Salesforce, Databricks, Oracle or Anthropic. All trademarks belong to their respective owners. · bxup.in