Skip to main content
Platform
Platform Overview How It Works
Solutions
AppSec Teams Platform Engineering Pricing Blog
Sign In Request Early Access
Shift-left security scanning in a CI pipeline with graph reachability context
Back to blog

Shift-Left Is Necessary But Not Sufficient for Modern AppSec

Moving security checks earlier in the development lifecycle is correct engineering practice. Catching a vulnerable dependency during a pull request review costs far less, in both developer time and organizational friction, than catching it during a production incident. That cost argument is well established and largely uncontested at this point. Shift-left investment has become standard practice across most engineering organizations that take application security seriously.

The problem is not that shift-left is wrong. The problem is that shift-left investment has been marketed as a solution to the wrong problem. The original framing was about cost of remediation: catch it earlier and it costs less to fix. That framing is accurate. But somewhere along the way, "shift-left" became conflated with "reduce security risk," and those two things are not the same. Shifting the timing of detection does not, by itself, change how many findings land in the queue or tell you which of those findings represent genuine exposure in your specific deployed application.

What shift-left scanners actually produce

A SAST tool running in CI does exactly what it is designed to do: it pattern-matches against known vulnerability signatures in your codebase and flags every match above its severity threshold. An SCA tool in CI does the same for your dependency graph: it checks declared versions against known CVEs and surfaces every package that meets the CVSS cutoff you have configured. Neither of these tools has any model of how your application is actually deployed, which services call which other services, which endpoints are exposed to external traffic, or whether the flagged code is in a path that an attacker can reach at all.

That is not a flaw in the tools. It is the scope of what static analysis at commit time can reasonably do. A scanner running on a PR has access to the changed code and the declared dependencies. It does not have access to your Kubernetes deployment topology, your service mesh egress rules, or the runtime call graph that emerges when twelve microservices interact under production load.

The prioritization gap that does not close

Here is what shift-left investment does not address: you run a scanner on every PR across every service in a 12-service application, and you accumulate findings at a rate that your AppSec team cannot process. The queue grows. Developers learn that the scanner flags things that rarely require immediate action. Oncall rotations start triaging scanner alerts the same way they triage low-severity monitoring alerts: with a quick glance and a "not now" decision.

Consider an AppSec team at a growing product company running that kind of architecture. Scanners on every PR, SCA on every dependency update. Total findings in the queue at any given week: well into the hundreds. The team has three AppSec engineers. They spend a significant share of their time not on analysis but on the mechanical work of sorting findings into "this matters" and "this can wait" without enough context to make that determination confidently.

The issue is that CVSS scores describe the intrinsic severity of a vulnerability in isolation. A CVSS 9.8 finding tells you the vulnerability class is critical, the attack vector is network, and authentication is not required. It does not tell you whether, in your specific application, the vulnerable function is reachable from any external entry point. In a deployed microservice architecture, a CVSS 9.8 in a library that is imported but whose vulnerable code path is never triggered by any external request is a different operational priority than a CVSS 6.5 in a library whose vulnerable function is called directly from a public-facing handler.

The deployment-topology problem

Shift-left scanning has another structural limitation that is specific to microservice architectures. The severity of a finding is topology-dependent in ways that a PR-level scan cannot see. A service that exposes an HTTP endpoint on the internal network only, behind a service mesh policy that allows calls only from one other service, has a very different exposure profile than a service that handles external traffic directly.

A scanner running at commit time sees the code. It does not see that the service it is scanning will be deployed with a network policy that prevents all external access, or that the API handler that calls the flagged function is protected by an authentication middleware that requires a valid service account token. Those deployment-time facts change the reachability verdict materially, and none of them are available to the shift-left tool.

This is not an argument against integrating scanners in CI. It is an argument that the output of those scanners needs to be filtered through a model of your running application before it reaches a triage queue. The scanner produces candidates. Reachability analysis determines which candidates are worth the team's attention given how the application is actually deployed right now.

Where the graph layer fits

The graph reasoning layer does not replace the shift-left scanner. It consumes the scanner's output and applies a filter: for each flagged finding, does any traversable path exist from an attacker-accessible entry point to the code location that was flagged?

That filter requires a model of your application's actual topology: which services call which, which endpoints are exposed to which traffic classes, what the call graph looks like from each entry point into the business logic where the vulnerability lives. Constructing that model requires combining static analysis of the codebase with runtime topology information from your deployment environment.

When both layers work together, the developer experience changes materially. A scanner alert that surfaces in a PR review now carries a reachability annotation: this finding is on a path reachable from external traffic, or this finding is in a code path that has no external entry point in the current deployment configuration. The developer reviewing the alert has the context to make a prioritization decision without routing it to the AppSec team for triage.

What we are not arguing

Shift-left investment is not a waste of resources. The argument here is narrower: shift-left alone does not close the prioritization gap that causes AppSec teams to spend their time sorting noise rather than remediating genuine risk. That gap is a different problem and requires a different tool. The scan runs early; the reachability filter determines whether the scan result requires immediate action, deferred action, or can be accepted as low risk in the current deployment context.

Reachability context does not make scanner findings disappear. A finding classified as unreachable today can become reachable tomorrow if the application topology changes. A new service that calls into the flagged code path, a new API route that exposes the handler to external traffic, a network policy change that opens a previously isolated service to broader ingress: any of these changes the reachability verdict. The graph model needs to be kept current, and findings classified as unreachable need to be re-evaluated when topology changes.

That ongoing evaluation is part of what makes this a layer that augments shift-left rather than replacing it. The scanner continues doing what it does well: catching known vulnerability patterns early, before they get buried in a release branch. The reachability layer does what the scanner cannot: tell you which of those findings sit on a path your threat model actually cares about.

See reachability analysis on your own code

Connect your repositories and apply a reachability filter to your existing scanner findings. No configuration changes to your current toolchain required.

Request early access