Skip to main content

Service

Source Code Review

Reading the code for the flaws that black-box testing structurally cannot reach.

Testing from outside finds what is reachable through the interface. Reading the code finds what is reachable at all, including paths behind feature flags, error branches that never fire in normal use, and the difference between a check that exists and a check that runs. Some vulnerability classes are close to invisible from outside and obvious in the source.

How this works

Trust boundaries first

The review starts by mapping where untrusted input enters and where it ends up: request handlers, message consumers, file and webhook ingestion, and scheduled jobs reading data somebody else wrote. Effort then goes to the paths between those and the dangerous sinks, rather than to reading the codebase evenly.

The sinks that decide severity

Deserialisation of untrusted input, template construction from strings, command and query building, dynamic attribute assignment, and anywhere a value chosen by a caller selects a code path. These are the constructs where a small mistake is remote code execution rather than a defect, and they are enumerable, so they are enumerated.

Authorisation as written

Whether the check is in the controller, where the next endpoint will forget it, or in the data layer, where it cannot be skipped. That single architectural fact predicts the presence of object-level authorisation bugs more reliably than anything else in a codebase, and it is only visible from the source.

Secrets, dependencies and the build

Credentials in the repository and its history, dependencies with known issues weighted by whether the vulnerable path is actually called, and the build and deployment configuration, which is code and is frequently the least reviewed code present.

What we look for

  • Deserialisation of data from any source the caller can influence
  • Templates built from strings rather than loaded from files, which is the whole of server-side template injection
  • Authorisation enforced per controller rather than in the data access layer
  • Recursive attribute assignment from user-controlled keys, which reaches class and global state in several languages
  • Cryptography used without authentication, fixed initialisation vectors, and ECB mode
  • Secrets in source and in git history, including ones removed from the working tree but still reachable
  • Error handling that fails open, and catch blocks that swallow the failure of a security check
  • Race conditions where a check and the action it guards are separate statements
  • Dependencies with known vulnerabilities on paths the application actually calls

What you get

  • Findings at file and line, with the data path from entry point to sink
  • The fix as a code change rather than a principle
  • Patterns rather than only instances, so one finding fixes the class
  • A short list of greps and checks worth putting in CI to stop the class returning

What this does not include

  • A tool report presented as a review: static analysis is used where it helps and its output is triaged, not forwarded
  • Code quality, style or architecture opinions unrelated to security
  • Writing the fixes, though the change is described specifically enough to implement directly
  • Review of dependencies' own source, beyond whether you call the affected path

Questions people ask

Do you need the whole repository?
Read access to the relevant services is best, including the build and deployment configuration and enough git history to find secrets that were removed from the working tree but not from the history. Where that is not possible, the review is scoped to what can be shared and the report says what was not seen.
Is this better than penetration testing?
It is different and the combination is stronger than either. Code review finds what is unreachable from outside and explains why a class of bug exists; testing proves what is exploitable in the deployed configuration. Where budget allows one, the answer depends on whether you need to know what is wrong or prove what is exploitable.
Which languages?
The vulnerability classes are largely language-independent and the review is directed at trust boundaries and sinks rather than at syntax. Where a language has its own specific hazards, those are covered explicitly, and if a stack is outside what can be reviewed properly that is said before the engagement rather than after.