ReleaseLock learn

The git tag was clean, the release wasn't: what the LiteLLM 1.107.0 compromise shows

Published November 2, 2026 · Sources checked November 2, 2026 (PT)

On October 21, 2026, LiteLLM's own release pipeline built, signed and published a malicious litellm==1.107.0 to PyPI and to its container registries. The official v1.107.0 source tag on GitHub did not contain the malicious files. If you checked the repo and the tag, everything looked fine. The lesson for anyone who installs software: reading the source is not the same as checking the thing you installed.

What happened

According to LiteLLM's root cause analysis, an administrative key for an internal service was committed to a public repository on May 27, 2026 and never revoked. On October 10, the attacker used it to get the GitHub CLI token of a LiteLLM organization owner, then used that access to collect tokens belonging to two other maintainers.

On October 21, seven litellm==1.107.0 wheels went out to PyPI between 11:39:51 and 11:40:13 UTC (4:39 to 4:40 AM PT), and Docker Hub and GHCR images followed at 11:46:56 UTC (4:46 AM PT). GitHub issue #47826 flagged the compromise about 20 minutes after publication, and LiteLLM says the artifacts were live for about two hours before they were pulled.

The tag was clean, the release wasn't

LiteLLM describes the release as built from a lookalike fork, then the history was cleaned. Its release workflows hardcoded BerriAI as the source owner. The attacker pushed workflow commit 9cf97e9, which added a source_owner input, and used the owner's token to override branch protection. The staging build then ran against the lookalike Berri-AI/litellm at commit 20535d8f, a commit that existed only on the attacker's fork.

After publishing, the attacker deleted the release run records, pushed a revert, and force-pushed main back to the commit before the change. main then showed neither the change nor the revert. LiteLLM notes both commits are still retrievable by SHA and the organization audit log recorded each override.

The chain in one line: real repo and real tag, release workflow quietly pointed at a lookalike fork, the project's own pipeline signs and publishes the fork build, then the workflow change is wiped from visible history.

Why signing and branch protection didn't save it

Branch protection did reject the first push. But an organization owner's token can override branch protection, and the attacker had one. A second stolen token approved the production gate.

Signing did what signing does: it proved the artifacts came from LiteLLM's pipeline. In LiteLLM's follow-up, the team says its otherwise unchanged pipeline built the fork, signed the images with its cosign key and published with its Trusted Publisher identity. A signature tells you who published something. It does not tell you the published bytes match the source you reviewed.

Why installing it could hurt even if you never used LiteLLM

Microsoft's analysis found the wheels shipped cook.pth, cook.py and sitecustomize.py, files Python can run during normal startup. An application did not need to import LiteLLM: starting Python in an affected environment could be enough. That is why Microsoft says not to run python or pip inside a suspect environment to check it, and why removing the package or a release tag is not enough recovery.

How to tell if the artifact matches the source

These checks come from Microsoft's guidance, plus tool docs for how to do each one:

None of these is a guarantee on its own. Together they make a quiet mismatch between source and artifact much harder to miss.

If you installed 1.107.0

Follow LiteLLM's incident post, which lists the affected artifacts, time windows and cleanup steps, and Microsoft's guidance, which includes its indicator list and hunting queries. We link to them rather than copy them so you always get the current version. In short: do not start Python in a suspect environment, rebuild from verified artifacts, and rotate credentials from a known-clean machine.

Check your tools on ReleaseLock

ReleaseLock tracks GitHub releases, not PyPI packages or container images. The same idea applies, though: a published artifact should be locked and checkable against something you already trust. For GitHub releases, look up a tool's lock level in the directory, and read Can this GitHub release be swapped? for what each level means. More incidents are collected in What 2026's GitHub supply-chain incidents show about unlocked releases.

Quick answers

What happened to LiteLLM 1.107.0?

On October 21, 2026, LiteLLM's release pipeline published a malicious litellm 1.107.0 to PyPI and its container registries. LiteLLM says an attacker with stolen GitHub tokens pointed the release workflow at a lookalike fork, so the release was built from the fork, then the history was cleaned. The artifacts were live for about two hours.

Why did the LiteLLM source history look clean afterward?

The official v1.107.0 tag never contained the malicious files, because the release was built from a commit on a lookalike fork. After publishing, the attacker deleted the run records, reverted the workflow change and force-pushed main back to its earlier state, so main showed neither change.

Why didn't signing stop the LiteLLM release?

Because the project's own pipeline did the signing. LiteLLM says its pipeline built the fork, signed the images with its cosign key and published with its Trusted Publisher identity. A signature proves who published an artifact, not that it matches the source you reviewed.

Could installing litellm 1.107.0 cause harm without importing it?

Yes. Microsoft found the wheels added Python startup files, so starting Python in an affected environment could run the payload even if LiteLLM was never imported. Microsoft advises against running python or pip inside a suspect environment.

What checks help catch a package that does not match its source?

Microsoft recommends hash-pinned lock files, verifying package and image provenance, using container digests instead of floating tags, and admitting packages to internal mirrors only after review.

Is the tool you install every day still swappable?

Look it up in the directory, or add the free scan step to your workflows.

Search the directory

Sources