Threat
LiteLLM Compromised, Steals Credentials
First reported · 2 reports wiz.io
Page published · Page updated
Earliest dated coverage: 21 Oct 2026 · First observed: 21 Oct 2026 · Latest dated coverage: 22 Oct 2026
Coverage timeline
Why it matters
LiteLLM's compromise warrants investigating credential theft on affected hosts and reviewing whether AI gateway logs expose tokens capable of authorizing software releases.
LiteLLM suspects attackers stole GitHub CLI OAuth tokens from its internal AI gateway logs to hijack its release workflow and publish malicious version 1.107.0. A follow-up investigation found that Claude Code sometimes embeds these tokens in response bodies that can be logged, but the attacker's initial access to the internal deployment remains unconfirmed. The malicious PyPI package and container images carried credential-stealing and backdoor code; affected artifacts were removed and involved tokens revoked.
Summary
On October 21, 2026, attackers distributed malicious LiteLLM version 1.107.0 through PyPI and container registries, including Docker Hub and GHCR. The package installed Python-startup hooks for a broad credential stealer and a separate remote-code loader. Affected container tags included v1.107.0, latest, main-latest and main-stable. Wiz identifies v1.106.2 as the most recent safe version in its reporting.[1][3]
The release compromise involved three engineers' GitHub accounts and apparently stolen GitHub CLI OAuth tokens. LiteLLM suspects that attackers collected those tokens from logs in its publicly exposed internal LiteLLM deployment, where an unexpected user account was discovered. Token exposure through logged Claude Code responses was observed, but the attacker's initial route into the deployment remains unconfirmed. The Hacker News additionally reports abuse of an organization-owner token, disabled branch protections and a workflow redirected to the lookalike Berri-AI/litellm repository, causing malicious artifacts to be signed and published.[1][3]
The incident progressed beyond malicious-package distribution. The Hacker News, citing Wiz, reports that attackers used stolen AWS instance-role credentials from compromised CI runners and Kubernetes nodes between 16:20 and 17:01 UTC, approximately 4.5 hours after exfiltration. Identity checks followed by model-listing calls were consistent with LLMjacking, while some environments also experienced IAM and broader discovery. Successful delivery through the separate remote-code loader is not established: Wiz found only initial test values in its GitHub dead drop before takedown.[1][3]
Defenders should treat execution of the malicious installation as a credential-exposure incident, not merely a package-removal task. The reporting recommends isolation, credential rotation, payload hunting and rebuilding affected environments. Containment timestamps differ by source: Wiz reports PyPI quarantine at 13:20 UTC and container removal around 13:53 UTC, while The Hacker News gives download-exposure cutoffs of 13:23 and 14:20 UTC respectively. No supported attribution connects this October operation to the March TeamPCP attack.[1][3]
Attack chain
- Suspected access to token-bearing application logs: LiteLLM found an unexpected account in its publicly exposed internal deployment and believes attackers obtained GitHub CLI OAuth tokens from its logs. The maintainers observed that Claude Code could include those tokens in response bodies that were subsequently logged. This is the suspected credential-acquisition route, not a confirmed initial-access sequence; access through a recently patched vulnerability remains a hypothesis.[1][3]
- Compromise of release authority: Malicious actions occurred through three engineers' GitHub accounts. Wiz quotes LiteLLM as saying one account triggered the project-releaser run and another approved it. The Hacker News reports that release permissions had been temporarily expanded for two engineers on October 19 and that an organization-owner token was used to disable branch protections and force-push malicious changes.[1][3]
- Workflow redirection and trusted-channel publication: The compromised workflow was pointed at Berri-AI/litellm rather than the legitimate BerriAI/litellm repository, resulting in poisoned artifacts being signed and published. Malicious version 1.107.0 reached PyPI at 11:39 UTC on October 21 and was also distributed through affected Docker Hub and GHCR tags.[1][3]
- Automatic execution during Python startup: Installation placed cook.pth, cook.py and sitecustomize.py directly in the site-packages root. Python startup processed cook.pth, which imported cook.py, and also attempted to execute sitecustomize.py. The payload therefore did not depend on an explicit application-level LiteLLM import.[1][3]
- Credential collection and exfiltration: The cook.py payload deobfuscated itself and ran privcollect to gather system, browser, developer, cloud and AI-tool secrets. Wiz describes encryption before HTTP POST exfiltration to /healthcheck on www.litellm.dev and identifies a stealer marker at /tmp/.pc_once_72129118c59f5636c0bb.[1][3]
- Parallel remote-code loading attempt: On Linux and macOS, sitecustomize.py launched a loader that obtained configuration from domain.txt in the letters9813/pythonclient-test GitHub repository before attempting to fetch and execute Python code from /codepy. The Hacker News describes an hourly daemon protected by /tmp/remote_code_loader.lock. Wiz found only initial test values in the dead drop before removal, so this branch's capability must not be confused with confirmed second-stage execution.[1][3]
- Observed use of stolen cloud credentials: The Hacker News reports that, approximately 4.5 hours after exfiltration, attackers validated stolen AWS instance-role credentials from compromised CI runners and Kubernetes nodes. Requests originated from 168.100.8.57 and 165.227.201.8 between 16:20 and 17:01 UTC. Each credential was checked with sts:GetCallerIdentity, followed by bedrock:ListFoundationModels and a ListModels call; some environments also experienced IAM and general discovery.[1]
Disclosure timeline
| Date | Event |
|---|---|
| 2026-10-19 | LiteLLM temporarily expanded release permissions for two internal engineers to publish daily customer bugfix backports, according to The Hacker News.[1] |
| 2026-10-21 11:39 UTC | Malicious LiteLLM version 1.107.0 was uploaded to PyPI.[3] |
| 2026-10-21 13:20 UTC | Wiz's later supplied snapshot states that PyPI had quarantined the malicious version by this time. The Hacker News separately gives 13:23 UTC as the end of its unpinned-pip exposure window.[1][3] |
| 2026-10-21 approximately 13:30 UTC | GitHub removed the letters9813/pythonclient-test dead-drop repository. Wiz reports that domain.txt had contained only initial test values before takedown.[1][3] |
| 2026-10-21 approximately 13:53 UTC | Wiz reports removal of the affected container images. This differs from The Hacker News's reported Docker exposure cutoff of 14:20 UTC; the supplied evidence does not reconcile the difference.[1][3] |
| 2026-10-21 16:20–17:01 UTC | The Hacker News reports attacker use of stolen AWS instance-role credentials from 168.100.8.57 and 165.227.201.8, including identity validation, model enumeration and discovery activity.[1] |
| 2026-10-22 | The Hacker News published its follow-up describing the suspected token leak through application logs, the release-workflow compromise and observed downstream credential abuse.[1] |
How it works
The confirmed release-compromise mechanism was abuse of account and workflow authority, rather than a demonstrated exploit against a specifically identified vulnerability. The reporting describes stolen GitHub CLI OAuth tokens, separate release-trigger and approval accounts, an organization-owner token used to remove branch protections, and a workflow redirected to a lookalike repository. Because the compromised workflow signed and published the artifacts, an artifact signature alone did not establish that its source was legitimate.[1][3]
The suspected upstream credential leak crossed an application-logging boundary. LiteLLM observed that Claude Code could place a user's GitHub CLI OAuth token in a response body; logging those bodies could expose the token in LiteLLM logs. The maintainers believe attackers accessed those logs in their exposed internal deployment, but have not confirmed how that access was obtained. A recently patched vulnerability is suspected, not established.[1][3]
The installed payload abuses two Python startup mechanisms. The cook.pth file imports cook.py from the site-packages root, while sitecustomize.py provides a separate startup execution path. Subsequent interpreter launches can therefore activate the malicious code without an explicit LiteLLM import. Wiz describes the simultaneous use of these two techniques as apparently the first documented case in the wild.[1][3]
The privcollect stealer uses 16 collection modules. The supplied Wiz text explicitly identifies credentials and cookies from Chrome, Firefox, Edge and Safari, and AWS credentials from ~/.aws/, environment variables and EC2/ECS instance metadata. It also describes broader system, developer, cloud and AI-tool collection. Collected data is encrypted and sent by HTTP POST to /healthcheck on attacker-controlled www.litellm.dev.[3]
The remote loader separates configuration from payload delivery: a GitHub-hosted domain.txt file supplies the destination for a subsequent /codepy fetch. The Hacker News describes a background daemon that acquires /tmp/remote_code_loader.lock and repeats the process hourly. This establishes a remote-code-loading capability, but not confirmed payload delivery; Wiz found that the dead drop never progressed beyond initial test values before takedown.[1][3]
Execution and forensic traces are platform-sensitive. Wiz reports that the remote loader's fcntl/fork usage is incompatible with Windows and that writing the stealer marker under /tmp/ can fail there. An absent /tmp/.pc_once_72129118c59f5636c0bb marker therefore cannot, by itself, exclude exposure on a Windows host.[3]
Affected versions and patch status
| Product | Affected | Patch status |
|---|---|---|
| LiteLLM Python package on PyPI | Malicious version 1.107.0. The Hacker News identifies unpinned pip downloads between 11:39 and 13:23 UTC on October 21, 2026, as impacted. The installed startup payloads make subsequent Python execution relevant to exposure assessment. | Wiz reports PyPI quarantine at 13:20 UTC and identifies v1.106.2 as the most recent safe version. The reporting recommends removing 1.107.0 and addressing credential exposure; it does not identify a later corrected release.[1][3] |
| LiteLLM container images on Docker Hub and GHCR | Tags v1.107.0, latest, main-latest and main-stable contained the trojanized package. The Hacker News gives an affected Docker-image use window of 11:46–14:20 UTC on October 21, 2026. | Wiz reports removal at approximately 13:53 UTC, differing from The Hacker News's 14:20 UTC exposure cutoff. Existing consumers still require investigation and remediation; registry removal does not reverse execution or credential theft.[1][3] |
Indicators of Compromise
| Type | Indicator | Context |
|---|---|---|
| domain | www.litellm.dev | Wiz identifies this attacker-controlled LiteLLM-lookalike hostname as the credential-exfiltration destination, using HTTP POST requests to /healthcheck.[3] |
| domain | litellm.dev | The Hacker News names this domain as the credential-exfiltration destination at /healthcheck. Its hostname rendering differs from Wiz's explicit www.litellm.dev; retain both in retrospective hunting.[1] |
| ip | 168.100.8.57 | Reported source of attacker AWS API activity using stolen instance-role credentials between 16:20 and 17:01 UTC on October 21, 2026.[1] |
| ip | 165.227.201.8 | Reported source of attacker AWS API activity using stolen instance-role credentials between 16:20 and 17:01 UTC on October 21, 2026.[1] |
| file-path | cook.pth | Malicious startup file installed in the site-packages root by LiteLLM 1.107.0; imports the cook module during interpreter startup.[1][3] |
| file-path | cook.py | Credential-stealing module installed in the site-packages root and loaded by cook.pth. Evaluate the filename in association with the affected installation.[1][3] |
| file-path | sitecustomize.py | Remote-loader startup payload placed in the site-packages root. The filename also has legitimate Python uses, so the malicious installation context and file contents are essential.[1][3] |
| file-path | /tmp/.pc_once_72129118c59f5636c0bb | Stealer execution marker identified by Wiz. Marker creation can fail on Windows because /tmp/ often does not exist.[3] |
| file-path | /tmp/remote_code_loader.lock | Lock file acquired by the background remote-code loader to prevent multiple instances. Its presence is an investigation lead, not proof of successful second-stage delivery.[1] |
| other | letters9813/pythonclient-test | GitHub repository used as the remote loader's dead drop, with domain.txt under main. Suitable for retrospective access-log hunting; the repository was removed and its file contained only initial test values at Wiz's analysis snapshot.[1][3] |
| other | Berri-AI/litellm | Lookalike GitHub repository used as the compromised release workflow's source, according to The Hacker News. Distinct from the legitimate BerriAI/litellm repository.[1] |
Key takeaways
- This was a compromise of release authority and artifact provenance: legitimate distribution channels and signing machinery delivered malicious code after account and workflow abuse.[1][3]
- Python startup behavior expands the exposure question beyond explicit LiteLLM use. The malicious installation placed executable startup hooks in site-packages.[1][3]
- Credential theft produced observed downstream cloud activity. Model enumeration supports Wiz's assessment of behavior consistent with LLMjacking, but the supplied reporting does not establish completed unauthorized model consumption.[1]
- Remote-code-loading capability and successful second-stage delivery are separate findings. The loader was present, but its dead drop contained only initial test values before takedown.[1][3]
- Neither the suspected initial-access vulnerability nor a connection to TeamPCP is established. Preserve those attribution and root-cause limits while responding to the confirmed release compromise and credential abuse.[1][3]
Defensive actions
- Remove LiteLLM 1.107.0, stop using the affected container artifacts, isolate affected hosts and rebuild environments where the malicious version executed. Use a verified safe release; Wiz identifies v1.106.2 as safe in its report.: The reporting explicitly recommends removal, isolation and rebuilding. Both Python-package and container distribution channels carried startup-executed malware, so package removal alone does not address prior execution.[1][3]
- Inventory installations and container use against the reported publication and exposure windows, including consumers of latest, main-latest and main-stable. Record the source-specific timing differences rather than treating one cutoff as conclusively reconciled.: The mutable tags were affected alongside v1.107.0. Wiz's 13:20 UTC PyPI quarantine and approximately 13:53 UTC container removal differ from The Hacker News's 13:23 and 14:20 UTC exposure cutoffs.[1][3]
- Hunt affected Python environments for cook.pth, cook.py and the malicious sitecustomize.py, together with /tmp/.pc_once_72129118c59f5636c0bb and /tmp/remote_code_loader.lock.: These are the documented startup payloads and execution artifacts. Assess sitecustomize.py in context, and do not clear a Windows host solely because the stealer marker is absent: Wiz documents a platform-specific marker-path failure.[1][3]
- Block communication with the reported exfiltration domains and review historical outbound requests to litellm.dev and www.litellm.dev, especially POST requests to /healthcheck.: The supplied sources identify these hostname renderings as the credential-exfiltration infrastructure, and The Hacker News explicitly recommends blocking the exfiltration domain.[1][3]
- Revoke or rotate every credential reachable from affected executions, including cloud, developer and AI-service credentials; include credentials obtained through environment variables and instance metadata in the exposure assessment.: The stealer collected broadly, and observed abuse involved AWS instance-role credentials from CI runners and Kubernetes nodes. The reporting recommends rotating all reachable credentials rather than limiting response to a single LiteLLM or LLM-provider key.[1][3]
- Review cloud audit records for requests from 168.100.8.57 and 165.227.201.8, prioritizing the reported 16:20–17:01 UTC interval and the sequence sts:GetCallerIdentity, bedrock:ListFoundationModels and ListModels. Examine related IAM and discovery activity.: These addresses and API patterns were reported in actual use of stolen credentials. Additional observed calls included ListRoles, ListUsers, ListAccessKeys, ListAccounts and DescribeTrails.[1]
- Investigate the remote-loader branch separately, including historical access to letters9813/pythonclient-test, the loader lock file and any retrieval or execution associated with /codepy.: The package contained an hourly remote-code-loading capability, and The Hacker News recommends investigating /codepy execution. Wiz's test-only dead-drop finding limits what is confirmed; it should not be reported as proof that a second stage executed.[1][3]
- For the compromised release environment, audit organization-owner and workflow-capable tokens, release approvals, branch-protection changes and workflow source-repository references. Check for the hyphenated Berri-AI/litellm repository.: The reported attack crossed multiple release controls using privileged tokens and a lookalike source repository. LiteLLM says the involved tokens were revoked, but the documented changes provide specific audit targets for reconstructing the compromise.[1][3]
- Examine potentially exposed LiteLLM response logs for GitHub CLI OAuth tokens and investigate unexpected accounts in the affected internal deployment. Revoke any exposed tokens identified by that investigation.: LiteLLM observed token-bearing Claude Code responses and discovered an unexpected account in its exposed deployment. The maintainers suspect this log-access route supplied the credentials used against the release workflow, although initial access remains unresolved.[1][3]
- Verify the exact package wheel and release version before admitting replacement artifacts into builds; do not rely solely on a clean source repository or an artifact signature.: The Hacker News relays advice to verify the installed wheel, and reports that the compromised workflow signed poisoned artifacts after sourcing a lookalike repository.[1]
Changelog
- Added a more specific suspected credential-acquisition route: GitHub CLI OAuth tokens could appear in logged Claude Code responses, and LiteLLM discovered an unexpected account in its publicly exposed internal deployment. Initial access remains unconfirmed; exploitation of a recently patched vulnerability is only suspected.[1][3]
- Expanded the release-compromise sequence with the October 19 permission expansion, organization-owner token abuse, disabled branch protections and workflow redirection to a lookalike repository that resulted in signed malicious artifacts.[1]
- Added observed post-exfiltration abuse of stolen AWS instance-role credentials, including two source IP addresses, the 16:20–17:01 UTC activity interval and model-enumeration and discovery calls. The incident now includes confirmed downstream credential use, not only collection capability.[1]
- Resolved the earlier ambiguous PyPI quarantine timestamp using Wiz's later explicit 13:20 UTC statement. Retained a separate timing discrepancy because The Hacker News reports exposure cutoffs of 13:23 UTC for pip and 14:20 UTC for Docker, compared with Wiz's approximately 13:53 UTC container removal.[1][3]
- Added an explicit attribution constraint: Socket, as quoted by The Hacker News, found no evidence establishing a connection between the October operation and the March TeamPCP attack despite similar use of a .pth startup hook.[1]