Skip to main content
Code Reviews Don't Catch Bugs (And Never Did)General
4 min readFor Security Engineers

Code Reviews Don't Catch Bugs (And Never Did)

The Conventional Wisdom

Your team reviews every pull request before it merges. Someone checks the logic, scans for obvious errors, and looks for security holes. You've built this into your software development lifecycle because code review is supposed to catch bugs before they hit production. It's a quality gate. It's how responsible teams ship software.

Except it isn't working. Production incidents still happen. Security vulnerabilities still slip through. And your reviewers are spending hours on a process that was never designed to do what you're asking it to do.

Why It's Incomplete

Code review as bug detection is a myth. Mark Dominus put it bluntly: "anyone who depends on code review to find bugs is living in a fool's paradise." This isn't hyperbole. It's about the fundamental mismatch between what code review can realistically accomplish and what we've convinced ourselves it does.

Think about what you're asking a reviewer to do. They're switching from their own work to read someone else's code without the full mental model the author built over hours or days. They're scanning for logic errors in code they didn't write, edge cases they haven't thought through, and security implications they might not have the domain knowledge to spot. And they're doing this in 15 minutes before their next meeting.

The math doesn't work. The cognitive load doesn't work. The incentives don't work. Your reviewer is optimizing for "looks reasonable" and "I don't see anything obviously wrong," not for "I've verified this handles every edge case and won't introduce a vulnerability."

The Evidence

Look at your own metrics. How many critical bugs has code review actually caught in the last quarter? Not typos or style issues that your linter should handle. Not architectural suggestions that would've come up in design review. Actual bugs that would have caused production incidents.

Now compare that to bugs caught by your test suite, by static analysis tools, by your staging environment, by your canary deployments. Code review isn't even in the top three.

This isn't a failure of your team. It's a failure of expectations. Judah Taub notes that "the role of the engineer continues to move further away from the actual code and toward validating architecture, intent, and business logic." Your reviewers can't simultaneously verify implementation details, evaluate architectural decisions, catch security issues, and ensure maintainability. You're asking them to do four different jobs in one pass.

What to Do Instead

Redefine what code review is for. Stop pretending it's your bug-catching safety net. Start treating it as your maintainability gate.

Your reviewer should answer three questions:

Can I understand what this code does? Not "is it clever" or "would I have written it differently." Can someone unfamiliar with this component understand the intent without archaeological excavation? If your reviewer has to ask "what does this do," that's a failed review. Not because there's a bug, but because you're accumulating maintenance debt.

Does this fit our architecture? Is this the right abstraction? Does it introduce coupling that'll bite us in six months? Does it follow the patterns we've established, or is it inventing new ones without justification? Mikhail Golikov emphasizes focusing on maintainability rather than bug detection. This is where that focus pays off.

Are the security boundaries clear? Not "did you sanitize this input" (your SAST tool should catch that). Are the trust boundaries explicit? Is it obvious what's validated and what isn't? Does this change expand your attack surface in a way that needs discussion?

Everything else belongs in automation. Input validation? SAST. Logic errors? Your test suite. Code style? Your linter. Performance regressions? Your benchmarking pipeline. Race conditions? Your concurrency tests.

For compliance contexts, this matters more than you think. PCI DSS v4.0.1 Requirement 6.3.2 requires you to review custom code prior to release. It doesn't specify that review must catch bugs. It requires review to identify security vulnerabilities. That's a different job. You can satisfy the requirement with a combination of automated scanning and focused human review of security-relevant changes. You don't need bug hunting. You need threat modeling.

ISO 27001 Control 8.25 covers secure development lifecycle. Again, the control is about having a process, not about code review catching every defect. Your automated testing pipeline is part of that process. Your static analysis is part of that process. Code review is one component, not the entire safety net.

When the Conventional Wisdom Is Right

Code review absolutely catches bugs in one scenario: when the reviewer has deep domain knowledge of the specific system being changed and enough time to actually think through the implications. This happens most often with security-critical code, cryptographic implementations, authentication flows, and authorization logic.

If you're touching your session management, payment processing, or access control decisions, slow down. Get someone who understands the threat model. Give them time to think. That's not a standard PR review. That's a security design review disguised as code review, and it deserves different treatment.

Small teams with high context also get value from bug-focused review. If you're three engineers who all understand the entire codebase, you can catch each other's mistakes. But that's not scalable, and it's not what most teams are dealing with.

For everyone else, stop depending on code review to find bugs. Build a testing strategy that actually works. Use your review time to keep your codebase maintainable. And when you do find a bug in review, ask why your automated checks didn't catch it. That's your real action item.

Secure Software Development Framework (SSDF)

Topics:General

You Might Also Like