The Software Supply Chain Is Now a Lateral Movement Problem
On October 21, attackers pushed a malicious release of LiteLLM, a popular Python library with roughly 23 million weekly downloads. It went through the project’s own release pipeline to PyPI and its official Docker images.
Anyone who checked the official source tag on GitHub would’ve found nothing wrong, because the malicious files never touched it.
It’s the latest in a string of similar incidents this year. In May, an attacker abused TanStack’s CI/CD pipeline to publish 84 malicious package versions under the project’s trusted npm identity. In August, the ChainDrop campaign used stolen credentials to spread across more than 400 npm packages, many of them carrying valid provenance.
Each incident exposes the same uncomfortable truth: trusted software can become an attack path even when the controls around it appear to be working. Once malicious code gets a foothold inside a trusted environment, where can it go next? A build runner may hold cloud credentials or publishing permissions, and an internal service may connect to systems its callers can’t reach directly.
That’s why software supply chain security increasingly needs to be viewed as a lateral movement problem as much as a dependency problem.
The package is only the first hop
When a third-party component becomes a security concern, teams naturally start with the component itself:
- Is it vulnerable?
- Was it modified?
- Where is it running?
- Is there a safe version?
Those questions matter, but they describe only the entry point. A compromised package executing inside a developer machine or build environment may suddenly find itself next to source-control credentials, publishing tokens, cloud identities, Kubernetes access, internal APIs, and network paths to other systems.
At that point, the package has already done the important part by gaining execution inside something trusted. The environment determines what happens next.
Teams often picture the attack path as a straight line from a malicious package to a compromised application. It’s more useful to trace the full route: the malicious package lands in a trusted environment, picks up the credentials and access available there, and uses them to reach additional systems.

Two organizations can run the same compromised package and experience very different outcomes. In one environment, the malicious code may have nowhere useful to go. In another, it may be running alongside powerful credentials and broad internal connectivity.
The package provides the foothold. The environment determines the blast radius.
The risk hiding in the middle
Security discussions often focus on the two ends of the software supply chain. This includes the third-party component that might be compromised and the production system we ultimately want to protect. But a lot sits between them.
Artifact repositories, package proxies, CI caches, build platforms, internal developer tools, AI gateways, secrets services, and other shared infrastructure connect different parts of development and production environments. Teams often treat these systems as infrastructure plumbing, but they’re also security boundaries.
A shared service may be reachable by many environments. It may hold credentials, store data that other workloads later use, or connect to systems its callers can’t reach directly. A useful way to think about these systems is as brokers. They perform work on behalf of other workloads, which can extend a caller's reach beyond the broker itself.

From a policy perspective, nothing looks unusual: a build environment connects to an artifact repository, a release workflow connects to the same repository, and production retrieves artifacts from it. Every connection may be expected and approved.
The problem is that direct connectivity doesn’t show the full trust relationship. It doesn’t tell us what the shared service can do, what state it retains, or where it can communicate next.

A reachability view asks three additional questions:
- What can a workload make this service do?
- What can the service reach on its behalf?
- What does the service retain from other workloads?
An artifact proxy may connect to external registries. A build service may fetch source, sign an artifact, and publish it. A gateway may connect to internal APIs, cloud services, or databases. A workload may therefore have no direct connection to a sensitive system while still being able to influence a service that does.
Shared state matters, too. A cache written by one workflow may later be consumed by another, logs may retain credentials, and artifacts or metadata may move between environments that otherwise appear separated.
When a workload can influence a shared service, its reach may extend to the systems, credentials, and state behind that service.
Prevention doesn’t tell you the blast radius
Teams already have a strong set of tools to reduce software supply chain risk. They include dependency scanning, software bills of materials (SBOMs), protected branches, artifact signing, build attestations, malware detection, trusted publishing, and short-lived identities. These tools are still essential, but most of them are built to keep attackers out or to prove that code can be trusted.
They don’t fully answer what happens when that trust fails. A developer identity can be stolen, a trusted workflow can be modified, a legitimate build process can produce something malicious, or shared state can cross from a lower-trust environment into a higher-trust one.
That is where prevention and containment answer different questions. Prevention asks whether we can stop malicious software from getting in. Containment asks how much the compromise can reach if prevention fails.
Both belong in software supply chain security because the initial foothold is only one part of the eventual outcome.
How to limit what a supply chain compromise can reach
Supply chain containment doesn’t depend on one perfect control. The goal is to reduce the number of useful next steps available to an attacker after something goes wrong, and these five practices are a good place to start.
Limit the value of credentials
Use narrowly scoped identities and separate build, publishing, and deployment privileges wherever practical. Short-lived credentials help, but scope matters just as much because a credential that exists for only a few minutes can still cause significant damage if it has broad permissions.
Separate different trust levels
Development workflows, untrusted pull-request builds, release systems, and production should not automatically share writable state, credentials, or privileges. Where shared infrastructure is necessary, separate permissions and access policies as much as possible.
Reduce unnecessary connectivity
Build systems often have broad network access because it makes engineering easier, but malicious code receives that same access. If a workload only needs a small number of destinations, those should be the paths it gets.
The same principle applies to shared services. An artifact proxy may need access to a few registries, while an internal gateway may need a defined set of APIs. Neither needs unrestricted connectivity simply because it sits inside the network.
This is where segmentation becomes particularly valuable. Every unnecessary path removed is one fewer path an attacker can use after the initial foothold.
Treat developer infrastructure as sensitive infrastructure
CI systems, artifact repositories, developer portals, AI gateways, and build services may hold credentials or connectivity just as valuable as systems in production. They should be protected based on what they can reach and what they retain, not simply on whether they are considered internal.
Start with the blast radius
A straightforward way to apply this thinking is to choose a developer workstation, CI runner, build service, gateway, or artifact repository and assume it has already been compromised.
Then walk outward and look at what becomes available next:
- Credentials. What tokens, keys, or identities are available?
- Access. What can those identities authenticate to?
- Connectivity. Which systems can this environment communicate with?
- Shared services. Which intermediaries can it influence, and what can they reach or retain?
- Next hop. Does another system expose an additional credential, identity, or path?
This changes the exercise from simply finding a vulnerable component to understanding an attack path. The findings may look small individually, such as an overprivileged cloud role, a publishing token that should have expired, a shared cache, an unnecessary network path, or a log retaining credentials.
Together, those details decide whether the compromise stops at one workload or spreads much further.
Where can the breach go next?
We’ll continue depending on software we didn’t write, so patching, provenance, secure build pipelines, and trusted publishing will continue to matter. The goal isn’t to replace those controls but to plan for the moment when one of them fails.
Once malicious code is running inside something trusted, the most important question becomes where it can go next.
That means looking at the identities around the workload, the systems it can reach, and the shared services connecting different parts of the environment. The first foothold may be difficult to prevent every time, but the next one does not have to be automatic.
One compromised component should stay one compromised component.
See how Illumio helps you map what each workload can reach and close the paths an attacker could use after the first foothold. Book a demo today.



.webp)

