Most code review guidelines focus on correctness, performance, and readability. Security checks are an afterthought — if they appear at all. The result is that security review happens as a separate activity by a separate person on a separate schedule, which means it happens too late, on code nobody remembers writing, with no original context available.
This checklist is for everyone who reviews pull requests. Not just security engineers. The security review does not need to be exhaustive — it needs to be fast enough to happen during the normal review cycle, which means it needs to be structured so a developer can walk through it in five minutes without losing their mental model of the diff.
Authentication and Session Management
Start here. Authentication bugs are high-severity and often invisible in a diff because they appear as missing code rather than wrong code.
- Does every new endpoint that returns user data require authentication? Check for missing
authenticatemiddleware or missing@login_requireddecorator in new route handlers. - Does any code change touch session creation, session validation, or token issuance? If yes, verify: tokens have appropriate expiry, session IDs are generated with a CSPRNG (not
Math.random()), and logout actually invalidates the server-side session. - If password handling is involved, are passwords hashed with bcrypt, Argon2, or scrypt — not MD5, SHA1, or SHA256? The hashing algorithm matters as much as whether hashing happens at all.
- Is the new feature protected against brute force? Any endpoint that accepts credentials or one-time codes should have rate limiting. Check that rate limiting is applied to the endpoint, not just the frontend button that calls it.
Authorization and Access Control
Authorization failures are the most common vulnerability class in web applications. They are also the hardest to catch with automated tools because they require understanding the application's data ownership model.
- For every database query that returns records belonging to a specific user, does the query include a
WHERE user_id = ?filter (or equivalent tenant isolation clause)? Look specifically for any query that accepts a record ID from a route parameter and returns the record without a user ownership check. - If role-based access control is involved, are role checks enforced at the service layer, not just the presentation layer? A check that only prevents the UI from showing an admin button does not prevent an attacker from calling the underlying API endpoint directly.
- Are there any new admin endpoints or management APIs? Verify these are protected by an admin-specific role check, not just authentication.
- Does the change modify what data is returned in an API response? New fields in a response that expose sensitive user data (email, phone, internal IDs) may create information disclosure vulnerabilities that are not obvious from the diff alone.
Input Validation and Injection Prevention
This is the category where most static analyzers do their best work, but human review still catches patterns that automated tools miss — particularly around indirect injection paths.
- Does any new code accept input from user-controlled sources (request body, query parameters, headers, file uploads) and pass it to a database query, OS command, template engine, or HTML renderer? Verify parameterized queries are used for database calls; shell commands use argument arrays, not string concatenation.
- Is any user input rendered into HTML without escaping? Pay attention to cases where user data flows into a template or a React
dangerouslySetInnerHTMLprop — these are XSS entry points. - Does the PR add any new file upload handling? File upload endpoints should validate MIME type from file contents (not the
Content-Typeheader, which is attacker-controlled), limit file size, and store uploads outside the web root. - Are there any new XML parsing operations? If the parser is configured with external entity expansion enabled, you have a potential XXE vulnerability (CWE-611).
Secrets and Sensitive Data Handling
Secrets in source code are an embarrassingly common finding. They are easy to commit accidentally and difficult to fully remediate once they appear in git history.
- Does the diff contain any string literals that look like API keys, tokens, passwords, or private keys? Long random strings, strings starting with
sk-,AKIA,ghp_, or-----BEGINare worth checking. - Are any new environment variables introduced in the PR? Verify they are referenced via
process.env,os.environ, or the team's standard secret management path — not hardcoded inline. - Does the PR add any new logging statements that might log request bodies, headers, or user data? Logging sensitive data is a common accidental exposure vector, especially in debug-level log statements that occasionally get left in production code.
- Does any new code serialize internal objects and return them in an API response? Verify that the serializer is using an explicit allowlist of fields, not a catch-all
to_dict()that might expose internal fields.
Dependency Hygiene
Short but important. New dependencies deserve specific attention during code review.
- Does the PR add any new direct dependencies? For each new package, verify: it is the intended package (not a typosquat), it has active maintenance, and it does not appear in any known vulnerability advisories at the version being installed.
- Does the lockfile get updated alongside the dependency change? A PR that modifies
package.jsonorrequirements.txtbut does not update the corresponding lockfile should be sent back before review. - Does the PR update an existing dependency to a version with a known changelog? A major version bump to a security library (cryptography, JWT, HTTPS) warrants a quick changelog review to understand what changed.
On review speed: a reviewer who walks through this checklist on every PR will add approximately four to seven minutes to their review time for a typical feature diff. That is a worthwhile trade. In our experience, most security issues caught during PR review take under an hour to fix; the same issues found in a security audit or in production take days.
How to Use This Checklist Without Slowing Down Reviews
The goal is not to turn every PR into a security audit. The goal is to catch the obvious things that SAST misses and that every experienced reviewer already knows to look for, but sometimes forgets to check under time pressure.
A practical approach: print this checklist as a PR comment template and paste it on any PR that touches authentication, data access, or external inputs. Skip categories that clearly do not apply to the diff. A PR that only modifies frontend styling does not need an injection prevention review. A PR that adds a new API endpoint does.
The categories most worth prioritizing when time is short: authorization (access control failures are the most common vulnerability class), input validation for any new external input paths, and a 30-second scan for string literals that look like secrets. Those three checks, consistently applied, prevent the majority of security vulnerabilities that actually ship to production.