Every stolen-secret file in the LiteLLM breach archive is named the same way: a timestamp, then 127.0.0.1 [2].
That address is the most informative detail in the entire incident. It means the secrets were not intercepted in transit. They were read out of process memory on the victim's own CI runner, in-process, on the host, and only then packaged up. Resecurity's analysis is explicit that the dumps came from live CI/CD process memory rather than from anything crossing a wire [2].
If your defence against credential theft is watching what leaves your network, that defence was never engaged.
The chain, with dates
The story is usually told as "LiteLLM was compromised". That is the wrong end of it. Reconstructed from the three published analyses, the sequence ran like this:
19 March 2026. TeamPCP compromised aquasecurity/trivy-action, the GitHub Action wrapper around the Trivy security scanner [2].
19 to 24 March. Organisations running scheduled builds auto-installed the poisoned Action. It ran with whatever privileges their CI gave it, which for a scanning step is usually generous [2].
During execution. The Action exfiltrated LiteLLM's PyPI publishing credentials from inside a GitHub Actions runner [2].
24 March, 10:39 UTC. Using those stolen tokens, the attackers published litellm==1.82.7 and 1.82.8 to PyPI. Version 1.82.7 carried a malicious payload in proxy_server.py; 1.82.8 added a litellm_init.pth file, which Python executes at interpreter startup and which therefore runs before any application code and outside the protection of --ignore-scripts [1].
Roughly 40 minutes later, PyPI quarantined both [1].
On each infected runner. The SANDCLOCK stealer escalated to root and swept environment variables, SSH keys, cloud credentials, Kubernetes tokens, .env files, and in-memory secrets pulled from /proc/<pid>/mem [2].
Read the order again. A security scanner was the entry point. A package publisher was the second victim. The thousands of organisations that installed the poisoned LiteLLM were third. Nobody in that chain did anything unusual: they scanned their dependencies, they published a release, they installed a package.
The uncomfortable part about scanners
Supply chain advice usually terminates in "scan your dependencies". That advice is still correct. It is also worth noticing what a scanner is, structurally.
A scanner runs inside CI. It needs to see your whole dependency tree, which means it runs after checkout with your source present. It is invoked automatically on a schedule, so nobody is watching when it runs. And it is trusted enough that its network calls and file access do not look anomalous, because inspecting things is its job.
That is an unusually good position from which to steal credentials, and it was reached by compromising one widely-used Action rather than by attacking any of the downstream victims directly.
None of which means stop scanning. It means a scanning tool is a dependency with production-level privileges, and it deserves the same pinning, review and least-privilege treatment you would give a library that touches your database. Most teams pin their application dependencies to hashes and let their CI actions float on a tag.
Three teams counted it, three numbers came back
How big was this? The honest answer is that it depends what you count, and the published figures differ by a wide margin.
| Source | Measure | Figure |
|---|---|---|
| CloudSEK [3] | Potentially exposed organisations | 2,500+ |
| CloudSEK [3] | CI/CD pipelines potentially exposed | ~434,000 |
| Resecurity [2] | Recovered victim archive | 152.5 GiB |
| Resecurity [2] | Capture files | 415,427 |
| Resecurity [2] | Organisations in the archive | 898 |
| Resecurity [2] | Repositories in the archive | 2,038 |
CloudSEK is estimating exposure surface, everything the stolen credentials could plausibly reach. Resecurity is counting what is actually inside the recovered archive. Those are different questions and it is reasonable that they produce different answers, roughly 2,500 organisations of potential exposure against 898 with recovered artefacts.
Anyone quoting a single headline number for this incident is quoting one of these without saying which. When a breach figure matters to a decision you are making, find out whether it counts what could have been reached or what was demonstrably taken.
Resecurity's sample tells you what the attackers actually got. Across 1,073 recovered files they found 2,146 secret records, and roughly 98% of them were GitHub Actions tokens, alongside GitHub App private keys, AWS, GCP and Firebase credentials, container registry tokens, SSH keys and code-signing passwords [2].
Code-signing passwords in a credential dump is the line that should make you sit up. That is the material for the next supply chain attack.
The names, and what the counts imply
CloudSEK's high-confidence exposure set includes organisations most people would assume have this handled, with per-organisation secret counts attached [3]:
| Organisation | Secrets in the exposure set |
|---|---|
| X Corp (Twitter) | 3,459 |
| Deloitte | 462 |
| Cisco | 327 |
| John Deere | 185 |
| Orange S.A. | 180 |
AWS and Samsung also appear in the set [3].
The spread is the interesting part. A single compromised Action produced three-figure secret counts at some organisations and a four-figure count at another, from the same five-day window. That difference is not about who is more careless in general. It is about how many secrets a given CI environment holds in scope at once, and how long they live.
An organisation whose runners hold ten short-lived, narrowly-scoped tokens loses ten short-lived tokens. An organisation whose runners hold thousands of long-lived credentials in environment variables, because that was convenient, loses thousands. The blast radius was set months before the attack, by ordinary decisions about how much a build job is allowed to see.
That is the number worth checking in your own pipeline this week: not whether you ran the poisoned Action, but how many live secrets a single build job could enumerate if it wanted to.
What LiteLLM actually did
It is worth being fair to the project at the centre of this, because the framing "LiteLLM was breached" implies a negligence that the record does not support.
LiteLLM published its own incident note on 24 March, the same day, and updated it on 30 March [1]. They removed the packages, rotated maintainer credentials, engaged Google Mandiant for forensics, and stated plainly that the compromise appears to have originated from the Trivy dependency in their scanning workflow rather than from their own code [1]. They confirmed that "the codebase is safe and no malicious code was pushed to main" [1].
They then paused releases pending a supply chain review and shipped v1.83.0 through a rebuilt CI/CD v2 pipeline with isolated environments, stronger security gates and separated release stages [1].
Same-day disclosure, named forensics partner, a specific technical account, and a rebuilt pipeline before resuming releases. That is close to the model response, and a project that behaves this way after being used as a delivery vehicle deserves to be described accurately rather than as the villain.
The indicators, if you have not checked
The attack window is narrow and specific, which makes retrospective hunting genuinely feasible [1][2]:
- Any build between 19 and 24 March 2026 that ran
aquasecurity/trivy-action. - Files on CI runners matching
<YYYYMMDD>_<HHMMSS>_<microseconds>_127.0.0.1.txt. - Presence of
litellm_init.pth, or any install oflitellm1.82.7 or 1.82.8. - Outbound traffic to
models.litellm.cloudorcheckmarx.zone, neither of which is an official domain [1]. - JSON secret dumps carrying
"isSecret":truemarkers. - Anomalous GitHub Actions token activity in that window: unexpected pushes, package publishes, release modifications.
The FBI issued FLASH advisory FLASH-20260702-01 in July warning that affiliated actors are likely to weaponise harvested credentials long after the original intrusion [3]. Five months on, "we saw no impact at the time" is not evidence that nothing was taken. It is evidence that nothing has been used yet.
What this changes for agent stacks specifically
LiteLLM is an LLM gateway. It sits between your agents and your model providers, which means the environments running it are exactly the environments holding model provider keys, and those were in the harvest list [1][2].
Three things follow that are worth doing regardless of whether you were affected.
Treat CI actions as dependencies. Pin them to a commit SHA rather than a moving tag. A tag is a pointer somebody else can move, which is precisely what happened here.
Assume the theft is in-process. Egress monitoring did not catch this because there was no interesting egress until the aggregation step. The controls that would have helped are narrower runner privileges and shorter-lived credentials, not more traffic inspection.
Rotate model provider keys on the same schedule as cloud keys. Most teams treat an AI provider key as lower stakes than an AWS key. In an agent stack it usually is not: it is a live spending authority with no rate limit you did not set yourself.
The generalisable lesson is smaller and less comfortable than "audit your supply chain". It is that the tools you install specifically to reduce risk run in your most privileged environment, on a schedule, unattended, and they are worth exactly as much scrutiny as the code they are inspecting.
References
[1] LiteLLM — Security Update: Suspected Supply Chain Incident. Article
[2] Resecurity, report RES-CTI-2026-0814 — The LiteLLM Supply-Chain Attack: TeamPCP SANDCLOCK CI/CD Credential-Harvesting Campaign via a Backdoored Trivy GitHub Action. Article
[3] CloudSEK Threat Intelligence — LiteLLM Supply Chain Attack: 2,500+ Companies Exposed. Article