Cybersecurity

Secure code review: manual and automated

A secure code review reads your source code for security flaws, using a human reviewer and automated tools together. The tools catch known patterns and vulnerable dependencies quickly. The reviewer catches the flaws that need context, such as a missing permission check. You receive findings with file and line references, an explanation of each and a suggested fix.

Start a project

What a secure code review is

A secure code review examines the source code of an application to find security flaws before attackers do. Because the reviewer can see every line, they find problems that a tester working from outside may never reach: an administrator function with no permission check, a rarely used endpoint, or a debug route left in by mistake.

It differs from a penetration test, which attacks the running application and sees the deployed configuration but only the paths it manages to reach. It also differs from an everyday code review for quality, although both often happen in the same pull request process: the mechanics are the same, the questions are about security. See also the glossary entry.

Two layers: automated tools and a human reviewer

Neither layer is enough alone.

LayerWhat it findsIts limits
Static analysis (SAST)Dangerous patterns in your own code, such as SQL built from strings, weak hash functions and unsafe function calls.Noisy, with false positives. It does not know your business rules, so it misses most access control flaws.
Dependency scanningThird-party libraries with published vulnerabilities, including those pulled in indirectly.Knows only published issues. Many alerts do not affect your code and have to be triaged.
Secret scanningKeys, tokens and passwords committed to the repository, including its history.Can miss secrets in unusual formats.
Manual reviewAccess control, business logic, design flaws, cryptography misuse and anything the tools flag that needs judgement.Takes time, so it concentrates on the riskiest code first.

Run the tools on every change so the easy problems never reach a person. Keep the reviewer's time for the flaws only a person can see.

What reviewers look for

These categories do not depend on a programming language. They overlap with the OWASP Top 10, a good awareness baseline, though a review goes further.

  • Authentication and access control. Is every endpoint and action checked on the server, for the right user and role? Can a user change an ID in a request and read someone else's record? Are session tokens issued, stored and expired properly? Is multi-factor authentication enforced where it is promised?
  • Injection. Do database queries use parameters, or are they built from strings? The same question applies to operating system commands, templates and search query languages. See SQL injection and cross-site scripting.
  • Unsafe deserialisation. Does the code rebuild objects from untrusted data using formats that can run code? Some native serialisation formats, such as Python's pickle, can execute code while loading data, so they must never read input from an untrusted source.
  • Secrets in code. Keys, passwords and tokens in source files, or in configuration committed to the repository, including old commits. Rotate any secret that was committed, even if it was deleted later, because the history keeps it.
  • Cryptography misuse. Home-made schemes, hard-coded keys, predictable random values used for tokens, fast hashes for passwords instead of a purpose-built function such as Argon2, scrypt or bcrypt, and certificate checks switched off.
  • Error handling and logging. Internal stack traces shown to users, checks that fail open when an error occurs, and logs that contain passwords, tokens or personal data.
  • Third-party code. Vulnerable or abandoned libraries, packages added for a tiny feature, scripts that run on install, and versions that are not pinned.

Language and framework specifics

The categories stay the same across languages, but the traps differ.

StackTypical places to look
JavaScript and TypeScript (Node.js, React)Inserting raw HTML into pages, such as dangerouslySetInnerHTML, eval, shell commands built from user input, prototype pollution when merging objects, and checks done only in the browser.
PythonLoading untrusted data with pickle or an unsafe YAML loader, SQL built with string formatting, and shell calls that include user input.
Java and KotlinNative object serialisation, XML parsers that allow external entities, SQL built by concatenation and, on Android, components exported to other apps.
Swift and mobile appsSecrets inside the app package, sensitive data kept in plain local storage instead of the system's secure storage, and certificate checks turned off.
Frameworks and ORMsRaw query escape hatches, mass assignment (request fields bound straight onto models) and routes added without the authentication layer.

Framework defaults, such as templates that escape output and queries that take parameters, remove whole classes of bugs. A reviewer therefore first checks where the code steps around them.

How a review runs, and what you receive

  1. Scope and context. Which repositories and branches, what the application does, and which data and roles matter. A threat model, if one exists, shows the reviewer where to spend time.
  2. Automated pass. Static analysis, dependency scanning and secret scanning, with the results triaged to remove false positives.
  3. Manual pass. The reviewer follows the highest-risk flows through the code: login, permissions, payments, file handling and admin features.
  4. Report. The findings are written up and prioritised.
  5. Walkthrough. A call with your developers to explain the findings and agree the fixes.
  6. Re-check. The reviewer confirms the fixes, ideally on the same pull requests that make them.

A useful report contains:

  • A summary for decision makers.
  • Each finding with its file and line, an explanation of why it is a problem, a severity and a suggested fix, often as a short code example.
  • A list of vulnerable dependencies and which to upgrade first.
  • A statement of what was and was not reviewed.
  • Suggestions for checks to add to your pipeline, so the same issue is caught automatically next time.

When in the lifecycle to review

Earlier is cheaper. Design flaws are best caught with a threat model before code exists. While building, review security-sensitive pull requests as they arrive. Before launch, run a focused review of the riskiest areas. Afterwards, review again when sensitive code changes, after an incident, and when you inherit a codebase from another team or supplier, because you cannot assume that anyone checked it.

Continuous pull request review or a one-off audit

ApproachStrengthsWeaknessesFits
Pull request reviewCatches problems while the author still remembers the context. Cheap to fix. Builds team habits.The reviewer sees a change, not the whole system, and it depends on discipline.Teams that ship often.
One-off auditLooks at the whole codebase with fresh eyes. Useful as evidence for other parties.A snapshot: the code changes the next day, and findings can pile up.Before launch, inherited code and major milestones.

Most teams need both: automated checks and a short security checklist on every pull request, plus a deeper audit at milestones. That is how we think about secure app development: checks on every change and a deeper look at the moments that matter.

A code review finds what is in the code, not how the application is deployed. Pair it with penetration testing to check the running system, including server and cloud configuration.

Questions we get asked

  • No. Scanners find known patterns and vulnerable dependencies, which is valuable, but they rarely understand your business rules. A missing permission check looks like ordinary code to a tool. Run scanners on every change, and add a human review for authentication, access control and the flows that handle money or personal data.

  • It depends on the size of the codebase, the languages used, how much of it is security-sensitive and how much context the reviewer is given. A review focused on the riskiest flows is quicker than a full audit. A reviewer can only estimate after seeing the repository and agreeing the scope with you.

  • They need read access to the repositories in scope, and no more. Give read-only, time-limited access, list the repositories in writing, and agree how the code is handled and deleted afterwards. Do not share production credentials, and rotate any secret the review finds in the code.

  • A code review reads the source and can cover every path, including ones that are hard to reach from outside. A penetration test attacks the running application and sees its real configuration, but only the paths the tester reaches in the time available. Each finds problems the other can miss, so important systems benefit from both.

  • Yes, in the same way as any other code. Generated code can contain insecure patterns, outdated library choices or missing checks, and it reads as confident either way. Review it by the same rules and run the same automated scanning, whoever or whatever wrote it.

Keep exploring

Ready to build something secure?

Tell us about your product. We will reply with a clear plan.

Start a project

We would like to use Microsoft Clarity to see how visitors use the site, so we can improve it. It sets cookies and is off unless you accept. Cookie policy