On May 27, 2026, someone at LiteLLM committed a configuration file to a public repository. It held an administrative key to an internal experimental service. A follow-up commit deleted the file, and the key was flagged for revocation. According to LiteLLM’s own root cause analysis, “nobody followed through on revoking the administrative key,” so it was still valid more than four months later.
On October 10, an attacker used it. On October 21, a malicious litellm==1.107.0 shipped to PyPI, Docker Hub and GHCR.
That is the second time in seven months that the most widely used open-source AI gateway was turned into a credential stealer. When this post first ran in April, it covered the first time: a 12-day stretch in March when Trivy, Checkmarx, LiteLLM and Telnyx were compromised and Axios was hit in a separate attack. It closed by calling March “a preview.” The preview turned out to be accurate, but not in the way the original advice assumed. This update corrects what the April version got wrong, adds what happened after, and replaces the defensive checklist with one that would have helped in October as well as March.
What actually happened in March, corrected
The first version of this post leaned on early reporting, and some of it did not survive. Axios was not part of the same campaign. A “500,000 machines” figure traced back to a vx-underground estimate that Unit 42 itself treated inconsistently. A Mandiant quote about “1,000 SaaS environments” could not be traced to a linkable source, so it is gone. Here is the record as primary sources now state it.
| Date (2026) | Target | What happened | Actor |
|---|---|---|---|
| Mar 19 | Trivy | Malicious v0.69.4 release; 76 of 77 trivy-action tags and all 7 setup-trivy tags force-pushed |
TeamPCP |
| Mar 21 to 23 | Checkmarx | All 35 kics-github-action tags force-pushed; ast-github-action 2.3.28 poisoned |
TeamPCP |
| Mar 24 | LiteLLM | PyPI 1.82.7 and 1.82.8 published with a stolen token; 1.82.8 added a .pth startup file |
TeamPCP |
| Mar 27 | Telnyx | PyPI 4.87.1 and 4.87.2 backdoored; payload hidden in a WAV file | TeamPCP |
| Mar 31 | Axios | npm 1.14.1 and 0.30.4 shipped a malicious dependency for about three hours | UNC1069 (North Korea) |
Sources for the table: Aqua Security on Trivy, Unit 42 on Checkmarx, The Hacker News on LiteLLM, Help Net Security on Telnyx, and Help Net Security again on Google’s attribution of Axios to UNC1069.
Two corrections matter more than the rest. First, the Trivy compromise did not start on March 19. Aqua says attackers pulled a privileged token from a misconfigured GitHub Actions setup in late February, the team disclosed and rotated credentials on March 1, and by Aqua’s own account that rotation missed some still-valid credentials. The March 19 attack ran on a credential that survived the cleanup. Second, the LiteLLM window was short, but not as short as it looked. The bad versions went live at 10:39 UTC and PyPI quarantined them within about 40 minutes, yet LiteLLM told users to treat installs up to 16:00 UTC that day as suspect, per The Hacker News.
The highest-profile victim is unchanged. Fortune reported that Mercor, then valued at $10 billion, said it was one of thousands of companies hit through LiteLLM, while Lapsus$ claimed up to four terabytes of data. Mercor faced at least five class actions within a week. Those remain allegations.
The credentials outlived the incident
The April version treated March as an event with an end date. Six months of follow-up says otherwise.
The clearest case is the European Commission. CERT-EU found that an AWS API key taken through Trivy on March 19 was used the same day: the attacker ran TruffleHog to hunt for more secrets, then created a new access key and attached it to an existing user. The Commission’s security team got alerts on March 24. By the time ShinyHunters published the data on March 28, about 91.7 GB compressed had left, touching up to 71 hosting clients across 42 Commission services and at least 29 other EU bodies.
In July the FBI issued FLASH-20260702-01, which tells organizations to treat credentials stolen in the campaign as permanently compromised, because TeamPCP or affiliated actors could reuse them in later attacks. It names Trivy, KICS, LiteLLM and the Telnyx SDK, and lists the tpcp-docs and docs-tpcp exfiltration repository names as indicators. In August, CloudSEK built a lookup from roughly 434,000 captured files that maps potential exposure to more than 2,500 organizations. The Hacker News is careful to note those totals “are not a victim count.”
Then, on August 26, Australian police executed search warrants in Western Australia. Two men, 21 and 23, were charged with 14 offences, alleged to be principal participants in TeamPCP. The FBI’s Brett Leatherman said the malicious code “potentially compromised more than a thousand organizations worldwide.” Arrests do not recall stolen keys. Every token that was readable on a runner on March 19 or March 24 and was not rotated is still a live credential in someone else’s archive.
Even with operators charged, the playbook kept spreading. In May, a worm the industry named Mini Shai-Hulud, which researchers tied to TeamPCP, hit packages from TanStack, UiPath and Mistral AI. CyberScoop reported that it planted backdoors in .vscode/tasks.json and .claude/settings.json, so removing the npm package left the persistence in place. That is the detail AI teams should hold onto: the malware had learned where coding agents keep their configuration. (LiteLLM published a note on May 12 confirming it was not affected by the Mistral wave.)
October: no poisoned scanner required
The October compromise is worth reading closely because none of March’s defenses would have stopped it on the maintainer side.
The chain, from LiteLLM’s root cause post: the key leaked in May unlocked an internal service called the LiteLLM Agent Platform. That platform held a GitHub token, and it was not a scoped personal access token. It “was the GitHub CLI OAuth token associated with our GitHub organization owner.” On October 10 the attacker pulled it, used throwaway workflows to exfiltrate six repository secrets including maintainer tokens, and deleted the run records. Earlier that same week, LiteLLM had relaxed its release gate to allow “any two engineers to trigger and approve a release” during a push for faster bugfix backports. On October 21, the attacker used the owner token to override branch protection, pointed the release workflow at a lookalike Berri-AI/litellm repository, approved production with a stolen maintainer token, and published.
The payload, per LiteLLM’s incident post, “contained compiled malware which steals credentials and loads remote-code execution tools,” using cook.pth and sitecustomize.py to run at Python startup. LiteLLM’s analysis of the attacker’s movement inside its systems found “a primary focus on upstream inference API tokens.” Upwind researcher Lidor Machluf opened GitHub issue #47826 about 20 minutes after the wheels appeared. PyPI quarantined them at 13:23 UTC, roughly an hour and 43 minutes after publication. Docker Hub tags, including latest and main-stable, pointed at the bad image until 14:20 UTC. Socket’s analysis covers the stealer’s internals.
Three things changed between the March and October versions of this story.
The entry point moved from a dependency to identity. In March the attacker needed a poisoned scanner inside LiteLLM’s CI. In October the attacker needed one unrevoked key and one over-privileged token held by an internal agent service. SHA-pinning every GitHub Action in the world would not have touched that path.
The target moved to the gateway’s contents. LiteLLM’s cleanup steps tell users who ran 1.107.0 to rotate “every provider key stored in the LiteLLM proxy DB,” plus the master and virtual keys. A self-hosted AI gateway is a vault of every model provider key an organization holds. Stealing from it is the same economics the site described in the opaque-router analysis: whoever sits in the middle of your model traffic holds the keys to all of it.
The agent became part of the attack surface on the maintainer side, too. LiteLLM’s remediation post does not ban coding agents. It says: “We are not going to tell engineers to stop using Claude Code and similar tools. Instead we size the account to the risk.” Owner accounts can no longer be used through the API or the gh CLI, and “Regular users can never be owners or admins.” That is the same principle the site argued for giving AI agents their own scoped identities, now arrived at the hard way.
The forgotten key is the part I recognize. In 20 years of IT operations at a large telecom, the credential that caused the worst week was rarely the one in production. It was the one attached to a pilot that ended, a vendor integration someone stopped using, or a test harness nobody owned after a reorg. Everyone agreed it should be revoked; nobody’s ticket queue contained the revocation. LiteLLM’s fix for exactly that failure is unglamorous: secret-scanning alerts now open tickets that close only after revocation is confirmed.
The checklist, rewritten for both attacks
The April checklist (pin everything, audit AI dependencies, monitor registries, lock down CI, build an SBOM) still holds. It was written for March. This version is written for an attacker who might come through your dependencies or through your vendor’s identity system, and who wants your model keys either way.
- Pin exact versions and add a release cooldown. Teams pinned to
litellm==1.82.6in March and1.106.2in October were untouched both times. A 24-hour delay before adopting new releases would have outlasted both PyPI windows.latestandmain-stableDocker tags were inside the October blast radius, so pin images by digest. The site walked through install cooldowns for editor extensions in its post on the Claude Code extension backdoor; the same logic applies to PyPI and container registries. - Treat the AI gateway as a secrets vault, not a library. Keep provider keys in a secrets manager with per-key spend limits, give every app a virtual key, and know how fast you can rotate every upstream key at once. If the answer is days, that is the number to fix.
- Rotate on exposure, then verify the revocation. The Trivy rotation in March and the LiteLLM key in May failed the same way: the decision to revoke was made and the revocation did not happen. Close the ticket on proof, not intent.
- Pin GitHub Actions to commit SHAs and enforce it. GitHub has let administrators require full-length SHA pinning through the allowed-actions policy since August 2025. Aqua’s own guidance notes that an “Immutable” release badge did not stop tag force-pushes. The site’s Plugin4Shell coverage covers the same control for agent plugins.
- Never hand an agent or automation a human owner’s token. Use GitHub Apps or fine-grained, expiring tokens. If an internal tool needs organization-level power, that is a design problem, not a configuration detail.
- Check where coding agents store configuration after any incident. Mini Shai-Hulud survived package removal by writing to
.claude/settings.jsonand.vscode/tasks.json. Add those paths to your incident runbook alongsidesite-packagesand systemd user units. - Search for the known indicators even now. The FBI’s
tpcp-docsanddocs-tpcprepository names, Trivy v0.69.4, LiteLLM 1.82.7, 1.82.8 and 1.107.0, Telnyx 4.87.1 and 4.87.2. Aqua notes the malware used atpcp-docs-prefix, so search by prefix, not exact name.
The original post ended by saying AI infrastructure is now critical infrastructure. Seven months later that reads as too abstract. The narrower lesson from LiteLLM is that the dangerous object in an AI stack is the token: the publish token in March, the owner token in October, and the inference API keys the attacker was hunting both times. Track those like the production assets they are, and the next poisoned release is a version you skip instead of a breach you report.
