Source code assisted pentest

Give the testers the code. Keep the proof.

Withholding the source does not simulate a real attacker. It simulates an attacker on a deadline. Handing over the code changes the question from ‘what can someone find this quarter’ to ‘does this weakness exist at all.’

The strongest argument for source code assisted testing is economic. A real adversary is not bound by your statement of work. Denying the testers the source narrows what they can reach in the time you paid for, without narrowing what an attacker can reach in the time they are willing to spend.

What a source code assisted pentest is

A source code assisted penetration test is an authorized security assessment in which the testing team holds read access to the application source code while testing a running instance of that application. NIST SP 800-115 frames security testing along a spectrum of tester knowledge, from no prior information through to full knowledge of the target, and treats the choice as a scoping decision rather than a measure of rigour.[1]

The defining constraint is that the code is an input, not the deliverable. A finding qualifies only when the tester has reached the vulnerable behaviour on the running system and can reproduce it. The code explains why the behaviour occurs and which other call paths share the defect; the running instance establishes that it occurs.

How it compares to black box and grey box testing

ModelTester holdsAnswersWeakest at
Black boxOnly what is publicly reachableWhat can an unaided outsider find within the engagement windowDeep authorization and logic flaws behind authenticated, multi-step flows
Grey boxCredentials, some documentationWhat can an authenticated user or a compromised account reachDefects in rarely exercised code paths and in dependency usage
Source code assistedCredentials plus read access to source and infrastructure codeDoes the weakness exist, and everywhere it existsEstimating how discoverable an issue is to an external attacker
Secure code reviewSource, often without a running instanceWhich patterns in the code are dangerousProving exploitability and filtering unreachable findings

These are complements, not competitors. The common mature pattern is a source code assisted test as the recurring engagement, with an occasional black box exercise scoped specifically to measure external discoverability and detection response — which is a different question, answered by a different exercise.

What the source access actually buys you

The gain is concentrated in weakness classes where the vulnerable condition is invisible from the outside until precisely the right request is made. MITRE's CWE Top 25 is a useful frame for which categories these are.[5]

  • Broken object and function level authorization. The code shows which handlers check ownership and which inherit a check from a caller that a second route does not use. From outside, the two routes are indistinguishable until one is tried with the wrong identifier.
  • Business-logic and state-machine flaws. Discount stacking, replayed idempotency keys, refunds that exceed the original charge, and approval steps that can be skipped are visible as missing transitions in code and nearly invisible as traffic.
  • Multi-tenant isolation. Tenant scoping applied in an ORM base class but bypassed by one raw query is a single-line defect with total impact — and is essentially unfindable without reading the query layer.
  • Cryptographic misuse. Fixed initialization vectors, unauthenticated ciphertext, signature verification whose result is computed but never checked, and predictable token generation all look like healthy cryptography on the wire.
  • Secrets in history. A credential removed in the current tree but still present in an earlier commit is reachable to anyone who obtains the repository, and is invisible to any amount of external testing.
  • Reachability of dependency vulnerabilities. The code answers whether a flagged CVE is on a path your application actually calls, which is the difference between an urgent fix and a backlog item.

What to provide, and what to withhold

Under-provisioning access is the most common way these engagements underdeliver. The tester spends the first third of the window waiting on environment problems, and the remaining budget covers less ground than a black box test would have.

  1. Read-only repository access, including dependency manifests, lockfiles, infrastructure-as-code, CI configuration, and full commit history. History is where committed secrets live.
  2. A running instance that matches production configuration. A staging environment with debug mode on, authorization disabled, or a different database engine produces findings that do not transfer.
  3. Test accounts at every privilege level, including at least two accounts in separate tenants or organizations. Cross-tenant authorization cannot be tested with one account.
  4. The intended authorization model in writing. Without it, testers cannot distinguish a deliberate design from a defect, and you will receive both as findings.
  5. A named contact and an agreed stop condition. Rules of engagement, escalation path, and the definition of an unacceptable impact should be settled before testing starts.[1]

Withhold production data and live production secrets. Source access is about understanding the system, and neither of those improves the test — they only enlarge the consequences of a mistake.

How the engagement should run

  1. Map the attack surface from the code. Enumerate routes, message consumers, scheduled jobs, and administrative entry points. This list is routinely larger than the one the product team maintains.
  2. Locate the trust boundaries.Identify where untrusted input enters, where authorization decisions are made, and where privilege changes hands. OWASP's Code Review Guide organizes this well.[3]
  3. Form ranked hypotheses.Turn each suspicious construct into a falsifiable statement: “this endpoint should reject a document ID belonging to another tenant.”
  4. Test against the running instance. Attempt each hypothesis in order of impact, following the OWASP Web Security Testing Guide for technique.[2]
  5. Generalize every confirmed finding. Return to the code and find every other call site with the same defect. This is the step that separates a code-assisted test from a lucky one, and the step vendors most often skip.
  6. Retest after remediation. Replay the original proof, then test the adjacent call sites found in the previous step, because partial fixes are the norm.

How to judge the report you receive

PCI DSS penetration testing guidance is explicit that a report must document methodology, scope, findings, and the evidence supporting them, rather than presenting conclusions alone.[4] For a code-assisted engagement, apply four additional tests.

CheckWhat a good report showsWarning sign
Proof, not patternA request and response, or a state change, that another engineer can reproduce“The code appears to permit…” with no attempt recorded
File and line attributionEach finding cites the exact location and commit that introduced the behaviourFindings that could have been written without the repository
Completeness sweepEvery affected call site listed, not only the one that was exploitedOne instance reported and closed, then the same bug recurs elsewhere
Negative resultsNamed controls that were tested and held, so you know what the coverage wasOnly positives, leaving scope coverage entirely unstated

Common pitfalls

  • Accepting static output as findings.A scanner report with the vendor's logo is not a penetration test. Unreachable code paths generate confident, expensive noise.
  • Testing an environment that is not production-like. Differences in configuration, feature flags, and data volume change which findings are real.
  • Reporting severity without reachability. A critical weakness in a code path no request can reach outranks nothing. Severity should be a function of what the finding can actually touch.
  • Letting the evidence go stale. A code-assisted test is accurate for the commit it was run against. Without retesting on change, its accuracy decays at the speed of your merge queue.
  • Confusing the question. Source-assisted results describe whether a defect exists, not how likely an outsider is to stumble on it. Do not use one to answer the other.

Frequently asked questions

What is a source code assisted pentest?

A source code assisted penetration test is an authorized security test in which the testers are given read access to the application source code alongside a running instance of the application. Testers use the code to find and understand candidate weaknesses, then attempt to exploit them against the running system so that every reported finding is backed by observed behaviour rather than by reading alone.

What is the difference between a source code assisted pentest and a code review?

A secure code review reads the code and reports weaknesses it can identify statically; it usually stops at the point of saying a pattern looks dangerous. A source code assisted pentest uses the code as a map and then requires exploitation against a running instance, so the deliverable is a reproducible proof rather than a list of suspicious patterns. Many programs run both, because the code review finds issues in paths that are hard to reach at runtime.

Is a source code assisted pentest the same as white box testing?

They overlap but are not identical. White box testing describes the level of information the tester holds, which can include source code, architecture documents, infrastructure configuration, and credentials. Source code assisted testing specifically names source access as the addition. In practice most engagements sold as white box are source code assisted plus credentialed access, and most engagements sold as grey box are credentialed but not source assisted.

Does giving testers source code make the test less realistic?

It changes what the test measures, and that is usually the point. A black box test measures what an unaided outsider can find within a fixed time budget. A source code assisted test measures whether a weakness exists at all, which is the more useful question when the alternative attacker has months, a leaked repository, or an insider. It should not be used to claim that an external attacker could trivially find the same issue.

What access should we give a source code assisted pentester?

Provide read-only access to the application repository including dependency manifests and infrastructure-as-code, a running non-production instance that matches production configuration, test accounts at every privilege level including at least two accounts in separate tenants, documentation of the intended authorization model, and a named contact for scope questions. Withhold production data and production secrets.

Does a SOC 2 or PCI DSS audit accept a source code assisted pentest?

Generally yes, and assessors often view the additional access favourably because it increases coverage. Neither SOC 2 nor PCI DSS mandates the black box format. What they care about is defined scope, tester independence and competence, a documented methodology, evidence of findings, remediation, and retesting. Confirm the specific expectation with your assessor before scoping, because the requirement is set by the audit programme rather than by the testing method.

How much more does a source code assisted pentest find?

There is no credible universal multiplier, and any vendor quoting one should be asked for their methodology. The categories that reliably improve are broken authorization, business-logic flaws, insecure use of cryptography, injection reachable only through unusual call paths, and secrets committed to history. Categories that improve least are those already visible from outside, such as exposed services, missing transport security, and default credentials.

Primary sources

  1. NIST. SP 800-115: Technical Guide to Information Security Testing and Assessment
  2. OWASP. Web Security Testing Guide
  3. OWASP. Code Review Guide
  4. PCI Security Standards Council. Information Supplement: Penetration Testing Guidance
  5. MITRE. CWE Top 25 Most Dangerous Software Weaknesses