Agentic Code Review: Prompts That Catch Bugs Static Analysis Misses

Your linter passes. Your type checker is green. Your CI pipeline reports zero issues. And your code still has a race condition that'll take down production at 2 AM on a Saturday.
Static analysis tools are pattern matchers. They catch what they're programmed to catch: unused variables, type mismatches, formatting violations, known vulnerability signatures. They cannot reason about what your code is supposed to do. They don't understand that your authentication check runs after your data fetch, or that your cache invalidation misses a path that only triggers under concurrent writes.
That gap between "syntactically correct" and "actually correct" is where agentic code review lives.
The numbers behind the gap
CodeRabbit's December 2025 analysis of 470 open-source GitHub pull requests found that AI-co-authored code produced logic and correctness errors at 1.75x the rate of human-written code. Concurrency bugs appear at 2x. Excessive I/O patterns at 8x. None of these categories are things your linter catches.
The volume problem is real too. Teams are shipping more AI-written code every month, which means more bugs going through the same linters.
But here's what makes multi-pass review worth building: research from the CodeX-Verify paper (arXiv, November 2025) showed that single review agents averaged 32.8% accuracy on a small hand-labeled set of code samples, while four specialized agents combined averaged 72.4%. The paper reports that as a 39.7 percentage point gain from splitting one broad review into focused passes, measured against the average single agent, not the best one.
Why single-pass "review this code" prompts fail
When you paste code into an LLM and say "review this," you get a grab bag. Some style notes, a vague security concern, maybe a suggestion to add error handling somewhere. The model tries to cover everything and covers nothing well.
Worse, research from August 2025 (arXiv) found that when LLMs explain and then fix code in the same pass, they become more prone to false positives. They incorrectly flag correct code as buggy. The explain-then-fix loop creates a confirmation bias where the model talks itself into seeing problems that don't exist.
The fix is constraint. Each review pass gets a narrow mandate. One job. Specific outputs. No style commentary in the logic pass. No performance opinions in the security pass.
The three-pass review chain
The CodeX-Verify research tested every combination of review agents. The counterintuitive finding: the best two-agent combination wasn't Correctness + Security. It was Correctness + Performance, hitting 79.3% accuracy, which beat the four-agent average. More passes are not automatically better. This chain keeps Security as a third pass because logic-level security bugs need their own mandate, and it drops a Style pass, which your linter already covers.
Here's the chain that works.
Pass 1: Logic and correctness
This is the highest-value pass. It catches the bugs that make you mass-page your on-call rotation.
The Prompt:
You are a code correctness reviewer. Your ONLY job is to find logic errors,
not style issues, not performance concerns, not documentation gaps.
Review this code for:
- Off-by-one errors in loops, slices, and boundary conditions
- Race conditions or shared mutable state across concurrent paths
- Null/undefined access in conditional branches
- Exception handling that swallows errors or catches too broadly
- State mutations that violate expected invariants
- Missing edge cases: empty inputs, negative values, integer overflow
For each finding, provide:
1. The exact line(s) affected
2. A concrete input or scenario that triggers the bug
3. The expected behavior vs actual behavior
4. A fix
If you find no logic errors, say "No logic errors found" and stop.
Do NOT comment on style, naming, performance, or documentation.
Code to review:
[paste code here]
Why This Works: The explicit exclusion list ("NOT style, NOT performance, NOT documentation") prevents the model from drifting into low-value commentary. Requiring a concrete triggering scenario forces the model to reason through execution paths rather than pattern-match against common bug categories. The "say no logic errors found and stop" instruction prevents hallucinated findings when the code is actually correct.
Expected Output:
Finding 1: Race condition in session cache (lines 47-52)
Theget_or_create_session()method reads from the cache dict, checks for None, then writes back -- but this sequence isn't atomic. Two concurrent requests for the same user ID can both pass the None check, both create new sessions, and the second write overwrites the first, orphaning the first session's state.
Trigger: Two simultaneous requests with the sameuser_idhitting the endpoint within the same event loop tick.
Expected: One session created, second request gets the existing session. Actual: Two sessions created, first session's data lost.
Fix: Use a lock per user_id or switch todict.setdefault()for atomic read-or-write.
This is the category of bug that LLift, a framework combining LLMs with static analysis (published at OOPSLA 2024), used to find four previously undiscovered bugs in the mainstream Linux kernel. Static analyzers had already flagged these code regions as suspicious but couldn't resolve whether the bugs were real. The LLM could reason about the intended behavior and confirm them, and the Linux community acknowledged all four.
Pass 2: Performance and resource management
The second-highest-value pass, per the CodeX-Verify data. This catches the bugs that don't crash your app but make it slow, expensive, or eventually run out of memory.
The Prompt:
You are a performance reviewer. Your ONLY job is to find performance bugs
and resource management issues.
Review this code for:
- N+1 query patterns or unbatched database/API calls inside loops
- Unbounded data structures that grow without limits
- Missing connection/file handle cleanup (resource leaks)
- Algorithmic complexity issues (O(n^2) or worse where O(n) is possible)
- Unnecessary blocking calls in async code paths
- Memory allocations inside hot loops
- Missing pagination or streaming for large result sets
For each finding, provide:
1. The exact line(s) affected
2. The performance impact (time complexity, memory growth, or resource exhaustion)
3. A fix with the improved complexity
If you find no performance issues, say "No performance issues found" and stop.
Do NOT comment on correctness, style, or security.
Code to review:
[paste code here]
Why This Works: Performance bugs are specific and measurable, so requiring complexity analysis ("O(n^2) where O(n) is possible") forces the model to do actual reasoning about data flow rather than generic "this could be slow" observations. The resource leak category is critical because linters can't trace handle lifecycles across function boundaries.
Expected Output:
Finding 1: N+1 query in order processing (lines 23-31)
Thefor order in ordersloop callsdb.get_customer(order.customer_id)on every iteration. For 1,000 orders, this fires 1,000 individual SELECT queries.
Impact: O(n) database round trips where O(1) is possible. At 5ms per query, 1,000 orders takes 5 seconds instead of 5ms.
Fix: Collect unique customer IDs, batch-fetch withWHERE id IN (...), build a lookup dict before the loop.
Pass 3: Security review
The third pass focuses on vulnerabilities that require understanding intent and data flow, not just pattern matching against known CVE signatures.
The Prompt:
You are a security reviewer. Your ONLY job is to find security vulnerabilities
that require understanding code intent and data flow.
Do NOT flag issues that a standard SAST tool would catch (basic SQLi patterns,
hardcoded credentials in string literals, missing HTTPS). Focus on:
- Business logic authorization bypasses (IDOR, privilege escalation through
workflow manipulation)
- Injection vectors where user input reaches dangerous sinks through indirect paths
- Dependency confusion or hallucinated package names in imports
- Timing attacks in authentication or comparison operations
- Information disclosure through error messages, logs, or API responses
- Insecure deserialization or type confusion
For each finding, provide:
1. The exact line(s) affected
2. An attack scenario a malicious user could execute
3. The CWE category
4. A fix
If you find no security issues beyond what SAST would catch,
say "No logic-level security issues found" and stop.
Do NOT comment on correctness, style, or performance.
Code to review:
[paste code here]
Why This Works: The "Do NOT flag issues that a standard SAST tool would catch" instruction is the key differentiator. It forces the model to operate in the space between lint rules and human security review. Requiring an attack scenario prevents the model from flagging theoretical vulnerabilities that aren't exploitable in context. The CWE category requirement keeps findings grounded in established vulnerability taxonomies instead of invented categories.
Expected Output:
Finding 1: IDOR in document access (line 84)
TheGET /api/documents/{id}endpoint fetches the document by ID but only checksis_authenticated-- it never verifies the requesting user has access to that specific document.
Attack scenario: Authenticated user A increments the document ID in the URL to access user B's private documents.
CWE: CWE-639 (Authorization Bypass Through User-Controlled Key)
Fix: AddWHERE document.owner_id = current_user.idto the query, or implement a document-level access control check before returning the response.
Wiring it into your workflow
The chain runs sequentially or in parallel depending on your setup. Sequential is simpler: pipe the code through each prompt, collect findings, deduplicate. Parallel is faster: fire all three passes simultaneously, then run a fourth verification prompt that cross-references findings and removes contradictions.
For CI/CD integration, the pattern is straightforward. Run the chain on the diff, not the full file. Format findings as inline comments on the PR. Set a threshold: any correctness or security finding blocks merge; performance findings are advisory.
The verification step matters. A short final prompt like "Given these findings from three independent reviewers, identify any that contradict each other or that flag correct code as buggy" catches the hallucinated findings that erode developer trust. False positives are what make developers stop reading review comments, and a verification pass is the cheapest way to cut them.
What this won't catch
Agentic review isn't omniscient. It can't catch bugs that require runtime state it can't see. It won't find issues that depend on infrastructure configuration outside the code. And per Qodo's State of AI Code Quality report from June 2025, 76.4% of developers see frequent AI hallucinations and won't ship AI code without reviewing it, so every finding needs human judgment before you act on it.
The mental model that works: the Swiss Cheese model from safety engineering. No single layer catches everything. Stack your linter, your type checker, your SAST scanner, and your agentic review chain. The holes in each layer don't align.
Three focused passes beat one broad review. The prompts above are ready to copy. Try them on your last three PRs and see what they catch that your existing tooling missed.
Want to build custom review chains for your team's specific codebase and vulnerability patterns? Connect with Kief Studio on Discord or schedule a session.
Rather have someone set it up for you?
That's a fair call. LTFI, the agentic business operating system from Kief Studio, can set up the work these guides describe and run it with you. No website yet? Kief Studio will build you one for free.

