@@ · critical paths @@

A security code review checklist for auth, payments, and input handling

Othman Shareef · August 7, 2026 · 7 min read · The Craft of Code Review

Most review advice optimizes for throughput: smaller diffs, faster turnaround, fewer nits. Security-critical code is the place that advice goes to die. When a change touches authentication, payments, or anything that parses user input, the correct move is to slow down on purpose, and a security code review checklist is how you make that slowdown systematic instead of dependent on whoever happens to feel paranoid that day. Here is the checklist we run, and the policy that decides when it applies.

Slow down by policy, not by vibes

The defining property of security review is that your adversary gets unlimited retries. A logic bug fires when a user happens to hit it; a security bug gets hunted by someone motivated, with tooling, forever. That asymmetry is why security-critical paths belong in the highest tier of the scheme we described in review by blast radius, and why the routing must be mechanical: path-based rules (an auth/ directory, a payments service, anything touching session handling) that flag the PR before any human decides how carefully to read it. Deciding rigor per-PR under deadline pressure always resolves the same way. Policy exists so the decision is already made.

The security code review checklist

This is deliberately short. It will not replace a security team or a scanner; it is what a reviewer holds in their head while reading a sensitive diff. The categories map onto the recurring failures in the OWASP Top Ten, which is worth reading in full at least once.

  • Input validation at trust boundaries. Find every point where data crosses from less-trusted to more-trusted: request bodies, headers, webhooks, file uploads, messages off a queue. Each crossing validates type, length, and range on arrival, not three layers deeper where someone assumes it already happened.
  • Authorization on every new path. Not authentication: authorization. The classic escape is a new code path to an existing resource that skips the ownership check the old path had. Ask of every new handler and every refactored branch: who can reach this, and did anyone verify they may?
  • Secrets handling. No credentials in code, config defaults, or fixtures. Watch logs especially: the fastest way to leak a token is to log the request that carried it.
  • Injection surfaces. Anywhere a string becomes a query, a shell command, a path, or markup. Concatenation is guilty until proven parameterized, including in the migration scripts and admin tooling nobody considers production.
  • Error paths that leak. What does the caller see on failure? Stack traces, internal hostnames, timing differences between “no such user” and “wrong password.” Failure output is API surface; review it like one.

AI-generated code inherits average security posture

A growing share of the diffs hitting these paths were written by models, and models reproduce the security posture of their training data: average, generic, and confidently incomplete. Generated code tends to include validation that looks right while missing the trust boundary your specific architecture actually has, because the model cannot know where your boundaries are. Osmani’s agentic code review essay frames the general problem: generation got cheap, verification stayed expensive, and volume pressures reviewers into exactly the skimming that sensitive paths cannot tolerate. The checklist from reviewing AI-generated code applies double here: no security assumption survives on the model’s authority, and “the tests pass” means little when the same model wrote the tests.

The two-reviewer rule for tier-3 paths

For the highest tier (auth flows, payment mutations, crypto, anything handling regulated data) one reviewer is not enough, and not because one person is careless. Single reviewers have single perspectives, and the parallel-review evidence says perspectives barely overlap: different readers flag almost entirely different issues. Two independent reviews of a sensitive diff are close to two distinct filters, not one filter run twice, and the second filter is cheap relative to the incident it prevents. Independence is the operative word: two approvals where the second reviewer skimmed the first one’s comments is one review with extra ceremony. Have both read cold, then compare. When their findings differ, that difference is itself information about where the diff is hard to reason about.

Make the slow path cheap to invoke

The failure mode of every rigorous process is that people route around it. If the security tier means a week of delay and an argument, engineers will quietly scope their changes to dodge the trigger paths, and you will have built an incentive to hide risk. Keep the heavy tier light everywhere you can: automate the routing, keep the checklist to the five items above, timebox the two reviews, and let everything outside the sensitive paths flow at normal speed. The goal is a team where flagging your own PR as security-relevant is a reflex, because doing so costs a day of extra scrutiny rather than a week of friction. Slow is a choice you make on purpose, in one place, so you can be fast everywhere else.

Frequently asked questions

What should a security code review checklist cover?

Five areas catch most of what matters: input validation at every trust boundary, authorization checks on every new code path (not just new endpoints), secrets kept out of code and logs, injection surfaces wherever strings become queries or commands, and error paths that leak internals. Run it on any change touching auth, payments, or user input, regardless of diff size.

How is reviewing security-critical code different from normal review?

The pace and the stance. Normal review optimizes for throughput; security review is deliberately slow by policy, because attackers get unlimited retries against whatever you approve. You read as an adversary looking for the path around the check, not as a colleague confirming the happy path works. Highest-risk paths also warrant two independent reviewers rather than one.

Is AI-generated code less secure than human-written code?

It reliably reflects the average security posture of its training data, which is not the posture your threat model needs. Models produce plausible validation and authorization code that misses your system’s specific trust boundaries, and the volume they generate pressures reviewers to skim. Treat AI-written changes on sensitive paths exactly like human ones: same checklist, same slow tier, same two reviewers.

← All posts