Overview
Static analysis tools are used the way they should be, to enumerate candidate sinks and widen coverage, and every candidate is then verified by hand. Tool output alone produces a finding list dominated by false positives, which costs your engineers more time than it saves.
The review prioritises the code that matters: authentication, authorisation, tenancy boundaries, input handling on the paths that reach dangerous sinks, cryptographic use, secret handling, and the dependency graph. Where a vulnerability is confirmed, it is exploited against a running instance wherever possible, so the report contains a demonstration rather than a theory.
Engagement at a glance
- Languages
- JavaScript/TypeScript, Python, PHP, Java, C#, Go, Ruby, Kotlin, Swift
- Typical duration
- 5 to 15 working days, scaled to reviewable surface rather than total lines
- Approach
- Manual review, guided by automated analysis for coverage
- Standards
- OWASP Code Review Guide, OWASP ASVS, CWE
- Access
- Read-only repository access; on-premises review available
- Deliverable
- Findings pinned to file and line, with the exploit path and the fix
What is covered
Every item below is tested and recorded, so the report shows what held as clearly as what failed.
- Data-flow tracing from user-controlled input to dangerous sinks
- Authentication and session management implementation
- Authorisation and multi-tenancy enforcement
- Injection sinks, SQL, command, template, deserialisation
- Cryptographic use, key management and randomness
- Secret handling, configuration and environment separation
- Dependency and supply-chain risk, including transitive packages
- Business logic and state machine correctness
- File handling, upload and path traversal
- Error handling and information disclosure
- Security-relevant framework misconfiguration
- Infrastructure as code and CI/CD definitions
Test matrix
What is attempted in each class, and what it means when it works.
| Class | What is attempted | Typical impact |
|---|---|---|
| Input to sink | Every route handler traced through the call graph to database, filesystem, process and template sinks | Injection and remote code execution confirmed at source |
| Authorisation | Every enforcement point compared against every route and object accessor | The one endpoint missing the check that the other forty have |
| Tenancy | Every query examined for the tenant predicate, including raw SQL, reports, exports and background jobs | Cross-tenant leakage on paths black-box testing never reaches |
| Cryptography | Algorithm and mode selection, IV and nonce handling, key storage and rotation, randomness source | Encrypted data recoverable, tokens predictable |
| Dependencies | Direct and transitive packages matched against advisories, with reachability of the vulnerable function confirmed | Known CVEs that are exploitable in your code path |
| Configuration | Framework security settings, debug flags, CORS, cookie attributes, infrastructure definitions | Production running with development defaults |
What we commonly find
The forty-first endpoint
Authorisation applied consistently everywhere except the route added under deadline pressure, invisible from outside unless you know it exists.
A tenant filter missing from a background job
The request path is scoped correctly; the nightly export is not.
Cryptography assembled from tutorials
ECB mode, a static IV, or a key derived from something guessable, each of which makes the encryption decorative.
A vulnerable dependency that is reachable
Most advisory hits are unreachable in practice. The review confirms which few are callable from your code.
How the engagement runs
Scoping and threat modelling
Map the asset, the attacker profile, and what “compromised” actually means for this business. Rules of engagement, testing windows, excluded techniques and an escalation contact are agreed in writing before anything is sent.
Reconnaissance and surface mapping
Enumerate everything reachable: subdomains from multiple passive sources, every endpoint referenced in JavaScript bundles, exposed services, third-party integrations, and the assets nobody remembers deploying. Coverage is recorded per host, so what was not tested is as visible as what was.
Manual exploitation
Authenticated testing from every role, with at least two accounts per role. Business logic, authorisation boundaries, injection, race conditions and state transitions, with each candidate reproduced live before it is written down. Automated tooling contributes coverage; it never contributes findings.
Verification and impact
Every finding is reproduced in a fresh session, isolated to the single parameter that causes it, and pushed to its maximum realistic impact. A finding that cannot survive a clean-room reproduction does not appear in the report.
Reporting and retest
The report is written twice over: once for the engineer who has to fix it, once for the auditor who has to file it. A walkthrough session follows, then a retest of every finding, closed only when re-exploitation fails.
What you receive
Executive summary
One page for the people who approve budget: what was tested, what was found, what it means in business terms.
Technical findings
Each finding with severity, CVSS, affected component, full request and response, reproduction steps and a working proof of concept.
Attack chains
Where findings combine, the chain is written out end to end, from first request to demonstrated impact.
Remediation guidance
A specific fix for your stack and framework, with the corrected pattern, not a link to a generic reference page.
Audit mapping
Findings mapped to SOC 2, ISO 27001, PCI DSS, HIPAA and OWASP ASVS as applicable, so the report drops straight into an audit pack.
Retest and attestation
Every finding retested in a clean session after remediation, with a signed attestation letter for customers and auditors.
When to run it
- Alongside a black-box test, for coverage neither approach reaches alone.
- Before a major release or an architectural change to authentication or tenancy.
- When a customer or auditor asks for evidence of secure development practices.
- After acquiring a codebase, before taking on responsibility for it.
Questions
Do we have to hand over our source code?
Access can be read-only and time-limited on your own platform, restricted to specific repositories, or conducted entirely on your premises or in an environment you control. A mutual NDA is signed before access is granted, and code is never retained after the engagement closes.
How is this different from running Semgrep or Snyk in CI?
Those tools should be running continuously. They are good at pattern-level issues and known-vulnerable dependencies. What they cannot do is understand what your application is supposed to enforce. Authorisation gaps, tenancy leaks and business logic errors are not patterns; they are deviations from intent, and intent has to be read.
Can you review only part of the codebase?
Yes, and it is often the better use of budget. Authentication, authorisation, payment handling and the tenancy layer are typically reviewed first, since that is where the highest-severity findings concentrate.
Do you provide fixes or just findings?
Every finding includes the vulnerable code, the exploit path, and a concrete remediation: the corrected pattern in your language and framework, not a generic reference. Patch review after remediation is included.
How much does a secure code review cost?
Cost follows the size of the codebase in scope, its language and framework, and whether the review is full or targeted at specific components. A fixed quote follows a short scoping call, and targeted reviews of authentication, authorisation and payment code are usually the best value per hour.
Which languages and frameworks do you review?
The common server-side stacks: JavaScript and TypeScript, Python, PHP, Java, C#, Go and Ruby, with their major frameworks. Where a stack is unfamiliar, we say so at scoping rather than after. The classes being looked for are framework-independent; the sinks and the idioms are not.
Do you sign an NDA before receiving code?
Yes, before anything is transferred. Code is received through a channel you control, held only for the engagement, and deleted at closure. We operate under our own certified ISO/IEC 27001 ISMS, which is a material difference when the asset in question is your source code.
Can a code review replace a penetration test?
No, and it is not sold as one. A review sees code paths that testing cannot reach; testing sees runtime and configuration that code cannot show. Together they cover both. Where budget allows only one, the choice depends on whether your risk is in what you wrote or in how it is deployed.
Do you review third-party dependencies?
Yes, and specifically for reachability. A vulnerable dependency that nothing in your code path calls is a patching task; one that is reachable from an unauthenticated route is an exposure. The review says which few are callable from your code rather than handing you the whole advisory list.