Introduction
Automated tools find about 40% of security vulnerabilities in code. The other 60% — business logic flaws, race conditions, authorization bypasses, and subtle injection vectors — require human eyes. After fifteen years of reviewing code for security, here is what I actually look for in a code review, beyond what any scanner will catch.
Race Conditions and Time-of-Check-to-Time-of-Use
Check balance, then debit account. Check inventory, then process order. Check permission, then perform action. Any time there is a gap between checking a condition and acting on it, an attacker can modify the condition between the check and the action. I look for operations that should be atomic but are not — especially in financial transactions, resource allocation, and permission checks.
The fix depends on the context: database transactions with appropriate isolation levels, optimistic locking, or mutex/semaphore patterns. The important thing is recognizing the pattern during review.
Data Flow Through Trust Boundaries
I trace data from its entry point (user input, API call, file upload, message queue) through every function it passes through until it reaches a sink (database query, command execution, file system operation, HTML rendering). At each trust boundary, I ask: is this data validated? Is it encoded appropriately for its destination? Can it break out of its intended context?
The most dangerous flows cross multiple trust boundaries: user input that is stored in a database, retrieved by a different service, and rendered in an admin dashboard. Each service might trust data from the database, but the original user input was never sanitized. These second-order injection vulnerabilities are invisible to scanners and easy to miss in reviews if you only look at individual functions rather than the full data flow.
Error Handling and Information Disclosure
Stack traces, database error messages, internal IP addresses, version numbers — all of these leak through poor error handling and all of them help attackers map your application's internals. I look for generic catch blocks that log the full exception to the user, debug flags that are checked at runtime (and might be enabled in production), and error messages that include internal identifiers or system paths.
A security-conscious code review is slower than a functional code review. But finding a vulnerability before deployment costs 100x less than finding it in production — and infinitely less than finding it in a breach investigation.








