- Socket found two workflows in LiteLLM's GitHub repository, run on October 10 and 12, 2026, that referenced 20 secret names, 11 days before the October 21 release attack.
- Build systems hand secrets to any code that runs there, and short-lived branches left little in ordinary history.
- Review who can push, which secrets are branch-limited, and how long you keep audit logs and deployment records.
The break-in before the break-in
Most security stories start on the day the damage shows up. This one starts 11 days earlier, in a place few executives ever look: the automated system that builds and tests software.
Socket's researchers found that secret-collecting workflows ran in LiteLLM's GitHub repository on October 10, 2026. The attack on PyPI and a container image, which published malicious litellm==1.107.0 files, came on October 21. Socket says that makes the compromise window at least eleven days.
The lesson here is that a build system holds secrets and gives them to whatever code runs inside it. Anyone who can push code to the repository can ask for those secrets, and can do so in a way that leaves very little behind.
How the trick worked
A GitHub Actions workflow is a script that runs automatically when something happens in a repository. The malicious workflow was set to run on every push, to any branch. Socket notes that the attacker therefore did not need to touch the main branch at all.
GitHub withholds secrets from workflows triggered by pull requests from forks. A push inside the repository gets no such treatment. Socket concludes that placing this workflow required push access to BerriAI/litellm. It was not a pull request from an outsider.
The sequence ran twice. Each cycle began with a temporary branch, named with a ci-tmp prefix and a hex suffix, based on a real recent commit. One commit then added a file called cache.yml, titled "ci: bump cache config". The push started the workflow, and the branch was deleted. Starting from genuine work made the push look routine.
The October 10 workflow was 24 lines. It copied six secrets into a file, encoded the file, and posted it to a webhook.site address. A trailing "|| true" made the step report success even if the upload failed. The October 12 workflow was 97 lines and ran the same steps in six jobs. Five of those jobs were tied to named GitHub environments, which unlocks the secrets stored in each one.
What was targeted
Across both workflows, Socket counted 20 distinct secret names. The October 10 run took six. The October 12 run took 14 more and reused none of the first six. Socket's reading is that the second run "was not a retry of the first; it collected what the first did not."
Socket treats the first three secrets from October 10 as the most consequential. They include a GitHub token and the private key of a GitHub App, both credentials for the platform that hosts the code. That key is what signs the tokens GitHub uses to grant an app access. Holding it gives access that outlasts a single session, unlike a user token, which expires. The lists also include billable API keys for Anthropic, OpenAI, Together AI and AWS Bedrock, plus database and Redis passwords.
Two items matter for different reasons. One is a key for the organization's secret-scanning service, which could give an attacker sight of the alerts meant to catch this. The other is saved browser session state for a Linear account, which Socket says allows access without a password or multi-factor check.
A gateway project that connects to many model providers keeps many providers' keys in one place. That is our interpretation, not a finding of the report.
Why nobody saw it
The runs were short. The repository's Actions performance metrics, which Socket reviewed, show an average run time of four seconds and no job failures. The branches were deleted the same day. As of commit f2118fc, no workflow sits at that path on main.
The durable evidence was elsewhere. Each environment-bound job created a deployment record, and those records survive after the file is deleted. The latest deployment in the integration-redis environment is still marked Active. It carries the malicious commit's title and came from the ref ci-tmp-4d8517.
What is still not known
Socket cannot see from the Actions metrics which secrets were actually transmitted. It has not established how the attacker first got in. Socket itself does not assert that the October 10 collection enabled the October 21 release attack.
LiteLLM has published its own investigation. In Socket's summary, LiteLLM says the intruder started with an Agent Platform master key that was accidentally pushed to a public repository in May and left unrevoked. LiteLLM also says its audit logs link the GitHub token taken on October 10 to approval of the October 21 release.
The activity log ties all six branch events to one account. Socket stresses that this identifies the credential used, not the person holding it. A stolen session and legitimate use look the same. Socket also cannot say whether other cycles ran before October 10 or between October 12 and 21.
Questions to put to your team
Can any workflow on any branch read your production secrets? Ask who has push access, and whether secrets can be limited to protected branches and approved reviewers.
Does anyone alert on workflow files that are created and deleted within hours? Do you keep deployment records and the organization audit log long enough to reconstruct a quiet week?
Which keys are long-lived? Check that a key found in a public repository is revoked, not only removed. And ask why the key to your secret scanner sits where a build script can read it.
A deleted branch is not a deleted record. The gap is whether anyone is reading the record.
Produced by the WebPulse Newsroom with AI assistance from the original reporting credited below, and checked against that source by our editorial review. How we use AI.
Original reporting: Socket.





