What Is Code-Aware Application Security Testing?

Code-aware application security testing is a methodology in which the testing engine uses an application's source code to understand routes, authorisation logic and data flows, then performs targeted security tests against the running system. The repository provides context about what is worth testing; the running application provides the evidence needed to determine whether a suspected weakness is actually exploitable.
The problem it addresses is familiar to anyone who has triaged security tooling. Static analysis examines code without directly observing whether a suspected weakness is exploitable in the deployed application. Dynamic scanning tests the running application but has limited visibility into the code and logic behind the interfaces it can reach. Used independently, neither provides the same combination of repository context and direct runtime verification.
Definition: What Code-Aware Application Security Testing Means
Code-aware application security testing is a methodology that uses repository metadata to inform dynamic offensive attacks against a running application. The system analyses source code to discover unlisted routes, authorisation decorators, and complex multi-step flows that a blind scanner would never find. The goal is to move beyond pattern matching and start reasoning about how an application actually handles data and permissions.
Most traditional tools fall into two camps. Static Application Security Testing (SAST) analyses code without directly observing how a suspected weakness behaves in the deployed application. Dynamic Application Security Testing (DAST) tests the running application but has limited visibility into the internal code and logic behind the interfaces it can reach. Code-aware testing merges these by using the code to build a comprehensive map of the attack surface. It looks for specific patterns: which endpoints require authentication, which parameters control tenant IDs, and which routes handle sensitive billing logic. Once it has this map, it launches targeted attacks to see if those protections actually hold up. The repository tells the system what to attack, and the running application decides what actually gets reported as a verified finding.
This approach is aimed squarely at business logic vulnerabilities, the class that needs application context to recognise at all. When an attacker exploits an Insecure Direct Object Reference (IDOR) bug, they are not using a generic exploit string. They are exploiting a flaw in how the application verifies whether a requester is authorised to access or modify a particular object. A code-aware system can identify a controller that appears to lack the required object-level authorisation check and then attempt cross-user or cross-tenant access to determine whether the weakness is exploitable. This is not just scanning for known CVEs. It is an automated search for flaws in the logic your team wrote last Tuesday.
How It Works: Repository Context Meets Runtime Verification
The process begins with repository access. The testing engine clones the code and builds an internal representation of the application structure. Discovering an internal route does not necessarily mean it can be tested dynamically; runtime verification still depends on the testing environment being able to reach it. It builds a map of application entry points visible from the repository, including REST API endpoints, GraphQL operations, and internal webhooks that may be invisible to an external crawler. By reading the code, the system can infer security-relevant properties of each route, including authentication middleware, role checks, access-control helpers, and data-access patterns. It sees which decorators are used for Role-Based Access Control (RBAC) and which controllers handle data persistence. This allows the system to prioritise high-risk areas like password resets, payment processing, and administrative dashboards.
Next comes runtime verification. After mapping the routes, the system executes offensive payloads against a live environment (staging or production). If repository context indicates that a route should require authentication or authorization, and runtime testing demonstrates that the protected action can be performed without the required access, the system can report a verified finding. If a suspected weakness cannot be exercised in the running application, it can be deprioritized rather than presented with the same confidence as a runtime-verified issue. Combining the two views is what lets a team spend its attention on paths that were actually taken.
Verification is the key differentiator. Code-aware testing provides that context by linking code patterns to execution results. Borg uses this dual-context approach to find broken tenant isolation. The system identifies potential flaws in tenant isolation and verifies these findings during a dynamic session. If the application returns data from a different organisation, the bug is verified and the remediation steps are clear, because the system provides verified findings with reproduction steps.
How It Compares to SAST, DAST, and IAST
SAST is good at what it does: analysing source code for potential weaknesses such as unsafe data flows, insecure API usage, and hardcoded secrets, cheaply and on every build. What static analysis alone does not provide is direct evidence that a suspected weakness is exploitable in the deployed application, which can leave teams triaging findings that are unreachable, non-exploitable, or irrelevant in the actual runtime environment. Code-aware testing does not replace that scan. It adds the step of attempting to reproduce the suspected weakness against the running application before presenting it with the confidence of a verified finding.
DAST has the opposite constraint. A DAST scanner discovers an application by crawling it, so an endpoint with no link in the frontend is one it may never reach. That matters more than it used to, because much of a modern single-page or mobile backend is only addressable as JSON. Reading the repository surfaces routes that crawling would miss. It does not guarantee complete coverage of the API surface, and a route that exists only in generated configuration can still be missed.
Interactive Application Security Testing (IAST) is the closest relative. It instruments the application from the inside with an agent, which gives it genuine execution visibility that neither of the other two has. The trade is deployment: an agent has to run in the runtime, which is more work in serverless or heavily distributed setups. Code-aware offensive testing takes a different route to a similar place, using the repository for context and external probes for the attempt, so nothing has to be installed alongside the application.
| What it reads | What it establishes | Main limit | |
|---|---|---|---|
| SAST | Source code | That a pattern is present | Cannot tell you whether the match is reachable |
| DAST | The running application | That an input produced a given response | Only tests what it can find by crawling |
| IAST | The running application from inside, via an agent | That a payload reached a sensitive sink | Needs an agent deployed in the runtime |
| Code-aware offensive testing | Source code, then the running application | That a suspected weakness can be reproduced against the running application | Blind to behavior decided outside the repository |
What Code Awareness Actually Unlocks (and What It Doesn't)
Code awareness makes it possible to automate the discovery of complex authorisation bugs. Traditional scanners cannot tell if a specific user should be able to delete a resource, because they do not understand the relationship between the user and the data. A code-aware system sees that the 'DeleteResource' function expects a 'resource_id' and a 'user_id' but only checks if the 'user_id' is logged in. The system then automatically attempts to delete a resource belonging to a different user. This level of logic testing is usually reserved for manual penetration tests, but code-aware systems can perform it continuously.
That said, code access still leaves gaps worth being honest about. Code-aware testing is limited by what is defined in the repository. If your application relies on a third-party managed service that is misconfigured in the cloud console rather than in your Infrastructure-as-Code (IaC), the testing engine might miss it. It also cannot find vulnerabilities in closed-source binary blobs or legacy systems where code access is restricted. It is an application-level strategy, not a substitute for full network or infrastructure security.
Another limitation is the reliance on accurate code parsing. If your team uses a highly custom, homegrown framework that the tool does not recognise, the initial mapping might be incomplete. Despite these gaps, the increase in signal over traditional DAST is large. By focusing on the code your engineers actually write, you catch the exploitable bugs that scanners miss and that attackers prioritise.
Code-Aware Testing at the PR Level vs Full Application Testing
One of the most powerful applications of code-aware testing is at the Pull Request (PR) level. Instead of waiting for a weekly scan or an annual pentest, the system can analyse every code change as it is proposed. When a developer modifies a sensitive file, such as an auth middleware or a billing controller, the system performs a security review of the changes. This allows security teams to catch broken access control before the code ever reaches production. This is the core of Borg's Gungnir feature, which focuses on the risk introduced by new code changes.
Full application testing is about the cumulative risk of the entire system. Even if every PR looks safe in isolation, the interaction between different services can create new vulnerabilities. A change in the identity provider might break an assumption in a downstream microservice. Continuous offensive testing at the application level catches these systemic issues.
Combining PR-level reviews and full application testing creates a safety net that traditional security models lack. Most teams rely on a point-in-time pentest that is obsolete the moment the next PR is merged. Code-aware testing means the security posture evolves alongside the codebase. If a new route is added in a PR, it is known about immediately and tested for auth bypasses on the diff rather than whenever the next assessment happens to run. Security becomes a continuous engineering process rather than a biannual hurdle.
Related Terms Worth Knowing
Understanding code-aware testing requires a basic grasp of several adjacent technologies. The first is Insecure Direct Object Reference (IDOR), a type of access control vulnerability where an application provides direct access to objects based on user-supplied input. Code-aware testing is built to find these by identifying ID-based parameters in the code and attempting to manipulate them during runtime. Another term is Attack Surface Management (ASM). While ASM focuses on discovering exposed assets like subdomains and IPs, code-aware testing focuses on the depth of the application surface once those assets are found.
Continuous Penetration Testing is the broader category that code-aware testing belongs to. This refers to the practice of performing offensive security assessments on a recurring basis rather than as a single event. You can read more about this in our guide on what is continuous pentesting. Finally, there is the concept of Tenant Isolation. In multi-tenant SaaS environments, ensuring that one customer cannot see another customer's data is the highest priority. Code-aware testing checks that isolation by reading how the code separates data at the database and API layers, then attempting to cross the boundary against the running system.
Linking these concepts helps security engineers build a more resilient defence. The goal is to move away from generic scanning and toward a model that understands the specific business logic of the application. Whether you are using Mjolnir for full application runs or Gungnir for PR reviews, the underlying principle is the same: use the code to inform the attack, and use the attack to verify the code.
Conclusion
Code-aware testing addresses a specific gap. Repository analysis alone cannot establish how a suspected weakness behaves in the deployed system, while black-box runtime testing has limited visibility into code paths and application logic it cannot discover. Using repository context to form targeted attack hypotheses and runtime testing to validate them combines the strengths of both approaches.
That combination is how Borg is built. Gungnir reviews pull requests touching auth, access control, APIs and billing. Mjolnir runs against the full application. Findings arrive with reproduction steps rather than as a list of matches. Book a walkthrough with Borg to see what that turns up on your own codebase.
Ofte stilte spørsmål
- Does code-aware testing replace manual penetration testing?
- No. It automates a class of work that is otherwise done by hand, particularly enumerating authorisation paths and checking whether each one holds, which rewards patience over creativity. What it does not do is replace a researcher reasoning about an unusual architecture, chaining an attack across several systems, or noticing that a design is wrong rather than that a check is missing.
- How does code-aware testing differ from static analysis?
- Static analysis reads code and reports what matches a pattern. Code-aware testing reads the same code to decide what to attempt, then attempts it against the running application and reports what worked. The difference is not the depth of the reading. One produces candidates; the other produces attempts with an outcome attached.
- Is it safe to run code-aware testing against a production environment?
- Treat that as a scoping conversation rather than a yes or no. Any offensive testing against production carries operational risk, so scope, timing, rate and which actions are permitted should be agreed before anything runs, and many teams point the first run at staging. Code context helps in that it narrows what gets touched to the paths that actually matter.
- Can code-aware testing find IDOR and broken access control?
- This is the class it is built for. Reading the repository shows where a record is resolved by an identifier supplied by the caller, and which of those paths carry an ownership check. The attempt against the running system then establishes whether a missing check is genuinely reachable, which is the part a static finding cannot tell you.
- What does code-aware testing not help with?
- Anything whose behaviour is decided outside the repository: a permission set in a cloud console rather than in infrastructure code, a third-party service misconfigured through its own dashboard, or a closed-source component you cannot read. Code awareness sharpens application-level testing; it is not a substitute for infrastructure or network security work.



