Cybersecurity

LiteLLM GitHub Breach Ran 11 Days Before Supply Chain Attack

Published By Shivam Sharma6 min read
LiteLLM GitHub repository breach and supply chain attack timeline illustration

On 21 October 2026, a poisoned version of LiteLLM went out to the world. Version 1.107.0 of the popular AI gateway carried an information stealer that ran on every Python startup, and it stayed live on PyPI for under two hours. The important part started 147 days earlier, with a key committed to a public repository and never revoked. Socket’s evidence, confirmed by LiteLLM, shows the attacker was already running secret stealing workflows inside LiteLLM’s GitHub organisation on 10 October, eleven days before the poisoned release.

What went out on 21 October

LiteLLM is an open source Python SDK and AI gateway for reaching different providers through one API. BleepingComputer puts it at 61,800 GitHub stars and 92 million monthly PyPI downloads, used by NVIDIA, Netflix, AT&T and Okta. The Register put it at about 23 million downloads a week. Neither counts poisoned build installs, and no confirmed installation count for 1.107.0 exists.

All seven PyPI wheels for litellm 1.107.0 were malicious, live from 11:39:51 to 13:23 UTC on 21 October. Docker Hub tags v1.107.0, latest, main-latest and main-stable pointed at the compromised image from 11:46:56 to 14:20 UTC, and the same GHCR tags were compromised until 13:51 UTC. The package added three files, cook.pth, cook.py and sitecustomize.py, to the Python library directory. Because Python runs .pth lines and imports sitecustomize at startup, the payload ran on every Python launch, even without importing LiteLLM, and investigating with Python or pip triggered it too.

The payload stole cloud and deployment credentials, AI credentials and configuration, developer secrets and private keys, browser data, and host data, encrypted it with AES-256-CBC under an RSA-4096 key, and uploaded it to litellm[.]dev/healthcheck. One file launched a loader that checked a GitHub hosted pointer hourly for further code. Customers on LiteLLM’s private enterprise release were not affected, according to BleepingComputer, and the recommended clean version is 1.106.2.

A key committed in May, never revoked

LiteLLM’s own attack chain post, published 23 October and described by LiteLLM as the canonical source of truth, traces initial access to 27 May 2026. That day, a configuration file in the public lite-harness repository contained the master key to a LiteLLM Agent Platform deployment. LiteLLM says the error was spotted quickly, the commit was force pushed over, and the exposed keys were flagged for revocation. The master key was never revoked.

On 10 October, the attacker used that key against the Agent Platform API. Between 21:13 and 21:28 UTC, authenticated requests returned, at 21:27:10, the configuration of every managed agent, including the GitHub CLI OAuth token of one of the organisation’s owners. From that point the attacker held owner level access to every repository in LiteLLM’s GitHub organisation. LiteLLM notes GitHub CLI tokens sit outside GitHub’s super user reauthentication flows for sensitive organisation actions.

Two quiet runs, two different hauls

Socket recovered two malicious commits, both adding .github/workflows/cache.yml under the subject “ci: bump cache config”. The first, commit b69bc36, ran on 10 October at 22:11:45 UTC on short lived branch ci-tmp-a351cc. The workflow was 24 lines with a single job. It read six secrets, GH_TOKEN, LINEAR_API_KEY, LITELLM_API_KEY, PROVIDER_INFO_SYNC_APP_ID, PROVIDER_INFO_SYNC_APP_PRIVATE_KEY and TOGETHER_API_KEY, wrote them to /tmp/c.env, base64 encoded it, and posted it to a webhook.site collector, with “|| true” forcing a success report. The branch and the run were deleted within minutes.

Twenty four seconds after that run, a second throwaway workflow on branch ci-tmp-be33e9 in BerriAI/litellm-auto posted RELEASE_PLEASE_TOKEN to the same endpoint. That secret held a third maintainer’s GitHub CLI token, which LiteLLM says matches the token later used to delete the release run records.

Two days later, on 12 October, the attacker came back with a bigger net. Commit 1a6e3c1 was 97 lines with six jobs, five of them bound to GitHub environments, and it collected 14 further secrets, including ANTHROPIC_API_KEY, OPENAI_API_KEY, AWS_BEARER_TOKEN_BEDROCK and GITGUARDIAN_API_KEY, plus PostgreSQL and Redis credentials and Linear browser session material. Across both workflows, 20 distinct secret names were referenced, with zero overlap between the two sets. Socket reads that as reconnaissance followed by broader collection. LiteLLM says the 12 October round took only minimally sensitive CI testing secrets, not on the path to the poisoned release, resolved by rotation and log audit.

One caution: GitHub’s metrics record both runs as successful, but whether the collector received every blob is not independently proven by the metrics alone.

How stolen tokens became a poisoned release

On 21 October, the attacker moved from stealing credentials to using them. A push to change the private project releaser workflow failed branch protection at 10:08:29 UTC, then succeeded five seconds later under the owner’s token. The pipeline was repointed to a lookalike repository, Berri-AI/litellm, instead of the legitimate BerriAI/litellm, and the staging workflow was dispatched at 10:46:39. At 11:11:18, the production gate was approved with the second maintainer’s token, the token LiteLLM links to the GH_TOKEN taken on 10 October. Seven wheels went out to PyPI between 11:39:51 and 11:40:13.

LiteLLM’s own account adds an uncomfortable detail. Building and publishing a release normally required an authorised engineer plus approval from a special account locked to a physical office device. That restriction had been relaxed that week to allow any two engineers to trigger and approve a release. The attacker used one stolen token to trigger the release and another to approve it. LiteLLM believes separate tokens were used to avoid noisy audit logs.

LiteLLM locked its registries and began revoking credentials.

What is confirmed, and what is still unproven

Confirmed: the May key exposure, the October workflows, the release chain, the payload behaviour, the exposure windows, and clean version 1.106.2. Unproven: how many installed or ran 1.107.0; whether every blob reached its collector; and who the attacker is. An earlier theory that the tokens came from deployment logs has been superseded: LiteLLM’s timeline says the first token came from the Agent Platform service via the May key. This was LiteLLM’s second supply chain compromise in 2026; the March figures sometimes quoted here (more than 2,500 organisations, 434,000 CI/CD pipelines, TeamPCP via Trivy) describe March, not October, and Socket told The Hacker News it found no evidence linking the two attacks.

As our analysis: the timeline is the warning

The unrevoked key lived 136 days, 2 hours and 19 minutes from its 27 May commit to the first observed abuse on 10 October. The pre attack window ran 10 days, 13 hours and 28 minutes from that first workflow to the first malicious PyPI wheels on 21 October at 11:39:51 UTC, so the “11 days before” headline counts calendar days, not elapsed time. Against all of that, the public blast lasted 1 hour 43 minutes on PyPI and 2 hours 33 minutes on Docker Hub. The visible incident lasted under three hours; the compromise behind it lasted more than four months. Our own arithmetic adds a check: The Register’s 23 million weekly downloads times four weeks equals BleepingComputer’s 92 million monthly downloads, so the outlets agree on project scale, though neither figure counts victims of 1.107.0.

If you ran 1.107.0, what to do

Stop affected deployments and inspect environments without launching Python, which triggers the payload. Isolate and rebuild affected systems from clean backups, rotate every possibly exposed secret, and move to the clean release 1.106.2. Removing the package directory alone may leave startup files or the hourly loader behind. Our earlier PHP2Shell coverage is a separate supply chain story and is not connected to the LiteLLM incident: PHP2Shell: the PHP flaw behind a wave of site outages.

Sources