The current OWASP Top 10 (the 2025 edition) again ranks broken access control first: 100% of tested applications had some form of it, with an average incidence rate of 3.74% and more than 1.8 million occurrences mapped across 40 distinct CWEs — making it the single most common category a reviewer will ever see cross a diff. MITRE's CWE Top 25, most recently refreshed in December 2025 from an analysis of tens of thousands of real CVE records, again puts cross-site scripting (CWE-79) in first place and SQL injection (CWE-89) in second — both defects that a careful human reviewer, not just a scanner, can catch by asking "where does this input come from, and where does it end up?" Most teams run a SAST tool on every pull request today, but tools miss context: a new endpoint with no authorization check, a hardcoded API key pasted in mid-review, a == comparison on a secret token that should be constant-time. This post is a checklist — independent of language or framework — for the things a human reviewer should look for on every PR, why each item matters, and how it complements rather than duplicates automated scanning.
What should a reviewer check first on any new endpoint or handler?
The first question on any new route, handler, or RPC method is whether it enforces authentication and authorization independently of what the client claims about itself. Broken access control's dominance in OWASP's current data — present in essentially every tested app — is largely driven by exactly this pattern: an endpoint that trusts a client-supplied user ID, role field, or object reference instead of re-checking permissions server-side, producing an insecure direct object reference (IDOR). A reviewer should ask three things for every new or modified handler: does it require authentication at all (easy to miss when copy-pasting a handler from an already-authenticated route group); does it check that the authenticated user is authorized for the specific resource being accessed, not just that they're logged in; and does the check happen before any data is read or mutated, not after. OWASP maps this category to 40 separate CWEs, including CWE-639 (authorization bypass through user-controlled key) — a pattern that shows up constantly in "fetch by ID" endpoints where the ID itself is the only access check.
How should a reviewer trace input to catch injection flaws?
A reviewer should trace every new piece of external input — query params, form fields, headers, file uploads, webhook payloads — from where it enters the code (the source) to where it's used in a command, query, or file path (the sink), the same source-to-sink reasoning that underlies automated taint analysis in SAST tools. MITRE's most recent CWE Top 25 (December 2025), built from tens of thousands of analyzed CVE records, ranks CWE-79 (XSS) first and CWE-89 (SQL injection) second — both are sink problems: untrusted data reaching an HTML template or a SQL string without encoding or parameterization. The reviewer-level check is concrete: does a diff introduce string concatenation or f-string interpolation into a query, shell command, or LDAP filter where a parameterized API or prepared statement was available instead? Does new template output pass through auto-escaping, or does it use a raw/unescaped-output helper ({{ value | safe }} in Jinja2, dangerouslySetInnerHTML in React)? These patterns are fast to spot once a reviewer is trained to look for the source-sink pair rather than scanning for "bad function names."
What secrets and credential mistakes slip through in diffs?
Hardcoded credentials are one of the easiest defects to catch in review and one of the most consequential to miss, because a secret committed to version control is compromised the moment it's pushed, regardless of whether the branch merges. A reviewer should scan every added line for API keys, database connection strings, private keys, or tokens — not just in application code but in test fixtures, example config files, and CI YAML, where developers often paste real credentials "just to get the test passing." The check extends to how a new secret is consumed, not just whether it's inline: is it read from an environment variable or secrets manager, or is it a literal string assigned to a constant? CWE-798 (use of hardcoded credentials) is one of the CWEs OWASP maps under its broader identification-and-authentication-failures and access-control categories, and it's uniquely suited to review because a linter can flag an obvious API_KEY = "sk-..." pattern, but only a human reviewer reliably catches a key smuggled into a base64 blob, a comment, or a debug log statement.
How should a reviewer evaluate cryptographic and comparison logic?
Any new code that compares secrets, tokens, or signatures deserves a specific check: is the comparison constant-time, and is the algorithm behind it current? A standard == or === comparison on a session token or HMAC signature short-circuits on the first mismatched byte, leaking timing information an attacker can use to guess a valid value byte-by-byte — a defect real enough that Safeguard's own PR Guard code-review feature flags exactly this pattern as a critical finding, recommending a constant-time comparison (for example, Node's crypto.timingSafeEqual ) in place of a direct equality check. Beyond comparisons, reviewers should flag weak or deprecated algorithms (MD5 or SHA-1 for anything security-sensitive), hardcoded initialization vectors or salts, and keys generated from predictable seeds. None of this requires cryptography expertise to catch structurally — it requires recognizing "this code touches a secret" as a trigger to slow down and check the primitive being used.
What deserialization and SSRF patterns should raise a flag in review?
Unsafe deserialization and server-side request forgery (SSRF) both share a pattern reviewers can learn to spot quickly: the application trusts a client-controlled value to determine what code runs or what internal resource gets fetched. Deserializing untrusted data with a format that can reconstruct arbitrary objects — Python's pickle, Java's native serialization, or YAML's unsafe loader — has produced remote code execution vulnerabilities across ecosystems for years; the review-level question is simply whether new deserialization code accepts external input and, if so, whether it uses a safe-by-default parser instead. SSRF follows the same shape: does new code fetch a URL, connect to a host, or resolve a redirect where the target address is wholly or partially attacker-supplied? A reviewer should check whether that URL is validated against an allowlist and whether internal/private IP ranges are explicitly blocked, since SSRF is routinely used to reach cloud metadata endpoints and internal-only services that were never meant to be internet-reachable.
How does human review complement automated scanning instead of duplicating it?
Automated tools and human reviewers catch different halves of the same problem, and a checklist works best when each side does what it's actually good at. Safeguard's own application security testing traces data flow from source to sink automatically across JavaScript/TypeScript, Python, and Java, mapping findings to CWE and OWASP categories at a scale no reviewer can match line-by-line. PR Guard, Safeguard's AI-driven pull request review, runs against the diff itself and returns severity-ranked comments — security, bug, reliability, and more — each tied to a specific file and line, with a suggested fix and a confidence score, and can post them directly onto the GitHub pull request so reviewers see them inline. What neither replaces is judgment: knowing that a new endpoint's authorization check is checking the wrong field, or that a "temporary" hardcoded credential in a test file was actually a production key, still requires a person reading the diff with the checklist above in mind. The most effective review process runs both — automated tracing for scale and consistency, human review for the context only a person on the team has.