Threat reportSupply ChainTL-2026-4042

LiteLLM Supply-Chain Compromise: Malicious v1.107.0 on PyPI and Container Registries Deploys 'privcollect' Credential Stealer and GitHub Dead-Drop Remote Code Loader

criticalACTIVE

LiteLLM Supply-Chain Compromise (TL-2026-4042), also tracked as LiteLLM Hijacked Again, is a critical-severity supply-chain compromise, first published 2026-10-21 and last reviewed 2026-10-26. It has no confirmed attribution, affects BerriAI LiteLLM (PyPI package litellm), maps to 49 MITRE ATT&CK / ATLAS techniques (AML.T0010.001, AML.T0055, T1005), and is covered by 9 detection rules and 69 indicators of compromise.

Severity
CRITICALAssessed severity
CVEs
0None referenced
Techniques
49MITRE ATT&CK / ATLAS
Actors
0Not attributed
Detection rules
9SPL · KQL · Sigma
IOCs
69Indicators of compromise

Key facts for TL-2026-4042

Threat ID
TL-2026-4042
Also known as
LiteLLM Hijacked Again, privcollect, Wiz-ADV-2026-188, XRAY-955589
Severity
CRITICAL
Status
ACTIVE
Category
SUPPLY_CHAIN
First published
Last reviewed
Attribution confidence
LOW
Motivation
UNKNOWN
Target sectors
technology, software development, artificial intelligence, cloud services
Target regions
Global
Detection rules
9
Indicators of compromise
69
Updates
2026-10-26 · 10 updates · revalidated 10× · latest source

Malware and tooling in LiteLLM Supply-Chain Compromise

Malware and tooling: Python, privcollect

How LiteLLM Supply-Chain Compromise works

On 2026-10-21 at 11:39 UTC a trojanized LiteLLM 1.107.0 was published to PyPI (all seven platform wheels) and shipped in LiteLLM container images on GHCR and Docker Hub (tags v1.107.0, latest, main-latest, main-stable). The wheels drop cook.pth, cook.py and sitecustomize.py into site-packages, which run on every Python interpreter start to steal system, browser, developer, cloud, CI/CD, AI-tool and LiteLLM proxy database secrets, encrypt them with AES-256-CBC/RSA-4096 and POST them to the lookalike endpoint www.litellm.dev/healthcheck, while a detached daemon polls a GitHub dead drop (letters9813/pythonclient-test) hourly to fetch and exec remote Python code. PyPI has quarantined the release; the last safe version is 1.106.2.

LiteLLM (BerriAI) is a widely deployed Python SDK and proxy/gateway that brokers calls to LLM providers and typically holds high-value provider API keys. On 21 October 2026 a malicious version, 1.107.0, was uploaded to PyPI. AISLE recorded the first malicious wheel upload at 11:39:51 UTC, flagged it at 11:43:05 UTC (3 minutes 14 seconds after upload) and had identified all seven wheels as malicious by 12:00:06 UTC. Wiz reported that LiteLLM Docker containers on GHCR and Docker Hub also included the trojanized version, affecting the v1.107.0, latest, main-latest and main-stable tags. PyPI subsequently quarantined the release (Wiz: 'quarantined on PyPI as of 1:20 UTC'), and the GitHub dead-drop repository was taken down as of 1:30 PM UTC. Aikido noted that at the time of its writing the Docker Hub image remained live. The last known-good release is 1.106.2; SafeDep additionally lists 1.107.0rc1 and 1.107.0rc2 as clean.

Injection vector: the payload exists only in the built wheel artifacts. SafeDep and Aikido found an extra maturin build directive in the wheel's pyproject.toml (`[tool.maturin] data = "cook"`) that copies a `cook/` directory into the wheel so that its contents land at the root of site-packages. The upstream GitHub tag v1.107.0 contains neither the directive nor the cook/ folder, and the sdist does not contain the three payload files, so reviewers inspecting only source, Git tags or the sdist would miss it. JFrog found the malicious wheels share ZIP timestamps and metadata with legitimate wheels, indicating injection during normal wheel construction rather than manual repacking. All analysts conclude either a compromised build/release pipeline or a stolen PyPI publishing token; the exact access path remains unknown.

Stage 1 - cook.pth / cook.py ('privcollect' stealer): cook.pth (12 bytes) contains `import cook` and is processed by Python's site module at every interpreter start, so the stealer runs inside every Python process on the host (applications, pip, IDEs, CI jobs). cook.py is a two-line wrapper of the form `exec(zlib.decompress(base64.b64decode('...')))` that unpacks ~61 KB of Python identified by JFrog as the 'privcollect' credential stealer. It runs in a daemon thread, sets `PRIVCOLLECT_ACTIVE=1` to avoid re-execution within the same process tree and writes the run-once marker `/tmp/.pc_once_72129118c59f5636c0bb` after a successful upload (the marker logic fails on Windows). Temporary artifacts `/tmp/.pc_sq_*` and `/tmp/.pc_e_*` are created during collection. Collection modules cover: system data (hostname, user, OS, IP addresses, network settings, process lists); Chromium-family browser passwords/cookies/history (Chrome, Edge, Brave, Vivaldi, Opera; DPAPI-decrypted on Windows) and Firefox logins.json/key4.db; ~/.ssh/*, GPG and TLS private keys and .pem/.key/.pfx/.p12/.pk8/.ppk files; bash/zsh/fish/PowerShell PSReadLine/cmd history; ~/.aws/credentials, Azure profiles, gcloud, ~/.kube/config, ~/.docker/config.json, GitHub CLI hosts.yml, rclone.conf, ~/.netrc; package-manager credentials (.npmrc, .pypirc, pip, Maven, Gradle, Composer auth.json, RubyGems, Cargo); FileZilla saved servers; Kubernetes service-account tokens; CI/CD secrets (GitLab runner config.toml, Jenkins initialAdminPassword and master.key, .vault-token, Terraform credentials.tfrc.json); AI developer tools (Claude Code, Claude Desktop, Cursor, Windsurf, GitHub Copilot, VS Code mcp.json, Gemini CLI, Hugging Face tokens); the process's own environment plus /proc/<pid>/environ of other processes on Linux; cloud instance metadata (AWS IMDSv2/v1 and ECS, Google Cloud, Azure via 169.254.169.254); and - LiteLLM-specific - a Prisma connection via DATABASE_URL to dump `LiteLLM_CredentialsTable` and `LiteLLM_ProxyModelTable`, which hold the LLM provider API keys managed by a LiteLLM proxy.

Exfiltration: collected material is encrypted with a per-payload random AES-256-CBC key, the key is wrapped with an embedded RSA-4096 public key using OAEP-SHA256, and the result is packed into a tar.gz containing hdr.json, data.bin and key.bin. The archive is POSTed over plaintext HTTP to `http://www.litellm.dev/healthcheck` - an attacker-controlled lookalike of LiteLLM infrastructure fronted by Cloudflare (AISLE: 104.26.10.8, 104.26.11.8, 172.67.73.104) - with headers `X-Token: XWiA8gZNa7NcX2XRoAEb` and `X-SHA256`, and User-Agent `Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0)` (Aikido).

Stage 2 - sitecustomize.py (remote code loader / RAT): Python imports sitecustomize automatically at startup. The module takes an exclusive flock() on `/tmp/remote_code_loader.lock` so only one instance runs per host, then fork()s and setsid()s into a detached daemon (PPID 1, own session, stdio to /dev/null, cwd /). Every 3,600 seconds it reads the first domain-like line from the GitHub dead drop `https://raw.githubusercontent.com/letters9813/pythonclient-test/main/domain.txt`, re-runs an embedded copy of the stealer (without the once-per-host marker), and downloads `http://<domain>/codepy`, executing it with `exec(compile(code, "<remote>", "exec"), {"__name__": "__main__"})` with no integrity verification. The attacker could therefore redirect infected hosts to new infrastructure simply by editing the GitHub file. AISLE reports the repository was created on 18 October 2026, three days before the attack; at analysis time domain.txt returned HTTP 200 with an empty body (the second stage was never armed), and the repository was removed by 13:30 UTC on 21 October.

Attribution and context: this is the second documented hijacking of LiteLLM in 2026. The first (24 March 2026, versions 1.82.7 and 1.82.8, litellm_init.pth, exfil to models.litellm.cloud and checkmarx.zone) was traced by LiteLLM to the compromised Trivy dependency in its CI/CD scanning workflow and attributed to TeamPCP (UNC6780). JFrog states that no evidence currently links the October 1.107.0 incident to TeamPCP or the earlier access path and that the incidents should be treated as separate campaigns; no source attributes 1.107.0 to a named actor. No source confirms observed victim infections. BeaconBeagle returned no C2 beacon or config matches for www.litellm.dev or its Cloudflare edge IPs. Any host or container that installed or ran litellm 1.107.0 should be treated as fully compromised: all reachable credentials, including every LLM provider key stored in a LiteLLM proxy database, must be rotated.

MITRE ATT&CK / ATLAS techniques used in TL-2026-4042

Initial Access

AML.T0010.001 AI Software; T1078 Valid Accounts; T1078.004 Valid Accounts; T1190 Exploit Public-Facing Application; T1195.002 Compromise Software Supply Chain

Credential Access

AML.T0055 Unsecured Credentials; T1528 Steal Application Access Token; T1539 Steal Web Session Cookie; T1552.001 Credentials In Files; T1552.003 Shell History; T1552.004 Private Keys; T1552.005 Cloud Instance Metadata API; T1552.007 Container API; T1555.003 Credentials from Web Browsers

Collection

T1005 Data from Local System; T1119 Automated Collection; T1213.003 Data from Information Repositories; T1213.006 Data from Information Repositories; T1560.002 Archive via Library

Discovery

T1016 System Network Configuration Discovery; T1057 Process Discovery; T1082 System Information Discovery; T1087.004 Account Discovery; T1217 Browser Information Discovery; T1526 Cloud Service Discovery; T1580 Cloud Infrastructure Discovery

Exfiltration

T1020 Automated Exfiltration; T1041 Exfiltration Over C2 Channel; T1048.003 Exfiltration Over Unencrypted Non-C2 Protocol

Defense Evasion

T1027 Obfuscated Files or Information; T1027.013 Obfuscated Files or Information: Encrypted/Encoded File; T1036.005 Match Legitimate Resource Name or Location; T1070 Indicator Removal; T1140 Deobfuscate/Decode Files or Information; T1480.002 Mutual Exclusion; T1550.001 Use Alternate Authentication Material: Application Access Token; T1562 Impair Defenses

Execution

T1059.006 Python; T1204.005 User Execution

Command and Control

T1071.001 Application Layer Protocol: Web Protocols; T1102.001 Dead Drop Resolver; T1105 Ingress Tool Transfer; T1573.002 Encrypted Channel: Asymmetric Cryptography

Persistence

T1546.018 Python Startup Hooks

Resource Development

T1583.001 Domains; T1583.006 Acquire Infrastructure; T1585 Establish Accounts; T1585.001 Establish Accounts; T1608.001 Upload Malware

Affected products and versions in LiteLLM Supply-Chain Compromise

  • BerriAI — LiteLLM (PyPI package litellm)
    Vulnerable versions: 1.107.0 (all seven wheels: macosx_10_12_x86_64, macosx_11_0_arm64, manylinux_2_28_x86_64, manylinux_2_28_aarch64, musllinux_1_2_x86_64, musllinux_1_2_aarch64, win_amd64)
    Fixed in: 1.106.2; 1.107.0rc1; 1.107.0rc2
  • BerriAI — LiteLLM container images (GHCR and Docker Hub)
    Vulnerable versions: v1.107.0; latest; main-latest; main-stable (as published 2026-10-21)
    Fixed in: Images built on v1.106.2

Remediation for LiteLLM Supply-Chain Compromise

Patches

  • Downgrade/pin to litellm==1.106.2 (last safe version) after cleanup
  • SafeDep also identifies 1.107.0rc1 and 1.107.0rc2 as clean; use only releases confirmed clean by BerriAI

Immediate actions

  • Identify every environment, CI runner, virtualenv and container that installed litellm==1.107.0 or pulled LiteLLM images tagged v1.107.0, latest, main-latest or main-stable on or after 2026-10-21
  • Check site-packages for cook.pth, cook.py and sitecustomize.py and remove them (and stale __pycache__) BEFORE running pip or any other Python process
  • Hunt for and remove /tmp/.pc_once_72129118c59f5636c0bb, /tmp/remote_code_loader.lock, /tmp/.pc_sq_* and /tmp/.pc_e_*, and terminate detached Python daemons (PPID 1, own session, cwd /)
  • Hunt for processes with PRIVCOLLECT_ACTIVE=1 in their environment
  • Block www.litellm.dev and raw.githubusercontent.com/letters9813/pythonclient-test at proxy/DNS; alert on HTTP POST to /healthcheck carrying the X-Token: XWiA8gZNa7NcX2XRoAEb header
  • Rotate ALL credentials reachable from affected hosts: LLM provider keys in LiteLLM_CredentialsTable/LiteLLM_ProxyModelTable, LiteLLM master/virtual keys, cloud (AWS/Azure/GCP) and instance-role credentials, Kubernetes service-account tokens, SSH/GPG/TLS keys, CI/CD and Vault tokens, package-registry tokens, AI tool tokens, and browser-saved passwords/sessions
  • Review cloud audit logs (CloudTrail, Azure Activity, GCP Audit) and LLM provider usage for use of stolen credentials since 2026-10-21 11:39 UTC

Workarounds

  • Run python with -S (skip site import) or -I only as a temporary containment measure when inspecting suspected hosts
  • Quarantine affected container images and redeploy from pre-2026-10-21 image digests

Longer-term hardening

  • Pin dependencies with hashes (pip --require-hashes / lockfiles) and pin container images by digest rather than mutable tags such as latest or main-stable
  • Enforce a package cooldown / dependency firewall so freshly published releases are not auto-consumed
  • Verify artifacts against source: compare built wheels to the upstream tag and sdist, and alert on unexpected .pth or sitecustomize.py files in site-packages
  • Restrict egress from LLM gateway and CI workloads to known provider endpoints; require IMDSv2 with hop limit 1
  • Store LLM provider keys in an external secrets manager rather than the LiteLLM proxy database where feasible
  • Rebuild affected environments and images from verified sources instead of in-place cleanup

Weaknesses (CWE) in LiteLLM Supply-Chain Compromise

CWE-506, CWE-494, CWE-829, CWE-522, CWE-532, CWE-798, CWE-540

Timeline of LiteLLM Supply-Chain Compromise

Showing the 20 most recent tracked events.

  • 10:08 UTC: branch protection bypassed using a stolen organization-owner GitHub CLI OAuth token (LiteLLM incident report); a second set of credentials later passed production approval gates.
  • Infected Docker images compiled 11:00-11:06 UTC and the malicious wheels built about 11:21 UTC from the attacker's Berri-AI revision, ahead of the PyPI upload at 11:39-11:40 UTC (StepSecurity).
  • LiteLLM security director Oliver Jensen confirmed to The Hacker News that three engineers' GitHub accounts were taken over. LiteLLM revoked the compromised tokens, removed every GitHub organization member except one unaffected account, and removed the trusted-publisher links between public registries and the organization. Companion packages litellm-proxy-extras 0.4.110 and litellm-enterprise 0.1.78 were verified uncompromised, and users were told to pin 1.106.2 by digest.
  • 14:32 UTC: BerriAI confirms removal of the infected Docker images; PyPI had removed 1.107.0 by ~13:23 UTC; account letters9813 and repo pythonclient-test deleted that afternoon.
  • Socket's scanner flagged the release at 11:46:30 UTC; the compromise was reported publicly in BerriAI/litellm issue #47826 at 12:06 UTC.
  • ~11:48-14:32 UTC: Docker Hub/GHCR floating tags latest, main-latest and main-stable pointed at the infected images (also ghcr.io/berriai/litellm-database and litellm-non_root:v1.107.0); GitHub release v1.107.0 published at 11:50 UTC.
  • 10:51-11:06 UTC: BerriAI release workflow run 39587059944 dispatched with source owner overridden to Berri-AI, so the official pipeline built and signed artifacts from the attacker's revision. BerriAI's root-cause statement, quoted by Wiz, attributes this to stolen GitHub CLI OAuth tokens of three engineers (one account triggered the run, another approved it); the tokens were later revoked.
  • 08:56-10:46 UTC: ten attacker commits pushed to the look-alike repo github.com/Berri-AI/litellm (author 'Berri-AI <ckdi82fkoos@proton.me>'), adding cook/purelib payloads, the maturin data = "cook" directive (783c43bc) and Dockerfile COPY cook (20535d8f).
  • Wiz (Wiz-ADV-2026-188), JFrog (XRAY-955589), SafeDep, Aikido and AISLE publish analyses and IOCs; Aikido notes the Docker Hub image was still live at time of writing
  • 13:30 UTC: GitHub dead-drop repository letters9813/pythonclient-test taken down; domain.txt had returned an empty body, so the codepy second stage was never observed armed
  • PyPI quarantines litellm 1.107.0 (Wiz: 'quarantined on PyPI as of 1:20 UTC'); last safe version 1.106.2
  • 11:43:05 UTC: AISLE dependency firewall flags the release 3 minutes 14 seconds after upload; all seven wheels confirmed malicious by 12:00:06 UTC
  • LiteLLM container images on GHCR and Docker Hub tagged v1.107.0, latest, main-latest and main-stable include the trojanized package (Wiz)
  • 11:39:51 UTC: first trojanized litellm 1.107.0 wheel uploaded to PyPI; all seven platform wheels carry cook.pth, cook.py and sitecustomize.py injected via maturin data = "cook"
  • Microsoft Defender detections become available: Trojan:PyPI/Stealer.SA, Trojan:PyPI/LiteLlmSupplyChain.A/.B and Backdoor:PyPI/LiteLlmSupplyChain.C.
  • LiteLLM publishes its incident advisory: the GitHub CLI OAuth tokens of three engineers (one organization owner) are suspected to have leaked via logs of an internal LiteLLM deployment exposed to the public internet (Wiz: tokens embedded in logged Claude Code response bodies). Wiz reports about 49,000 PyPI downloads of 1.107.0.
  • BleepingComputer reports the release-pipeline compromise; LiteLLM advises downgrading to 1.106.2, rebuilding from clean backups and rotating all exposed credentials.
  • Socket publishes evidence, recovered from GitHub Actions metrics, environment deployment history and the activity log, that the secret-stealing workflows ran on 2026-10-10 and 2026-10-12.
  • Microsoft publishes its analysis, reporting confirmed credential collection on Windows and macOS endpoints and tracking the issue as TVM-2026-0003 in Defender Vulnerability Management. Remote code retrieval or execution by the loader was not observed in its telemetry.
  • LiteLLM publishes its attack-chain postmortem and The Register reports the exposed Agent Platform master key as the root cause. The release pipeline was hijacked via commit 9cf97e9 to BerriAI/project-releaser, and a relaxed release-approval policy (two-engineer approval instead of physical-device authorization) allowed the production gate to pass.

Update history for TL-2026-4042

Sources cited for LiteLLM Supply-Chain Compromise

Detection coverage for TL-2026-4042

As of 2026-10-26, Threadlinqs Intelligence publishes 9 detection rule(s) for TL-2026-4042 across Splunk SPL, Microsoft KQL and Sigma, covering 69 indicator(s) of compromise. The whole corpus is readable without an account; a free account unlocks full detection query text in Splunk SPL, Microsoft KQL and Sigma; paid tiers add raw indicator values, correlation and the MCP server. Threadlinqs MCP server · View plans.

9 detection rules (Splunk SPL, Microsoft KQL, Sigma) · Blue and above. Compare plans
69 indicators of compromise · Red and above. Compare plans

Further reading

Threadlinqs Intelligence — Real-Time Threat Detection Platform

[ 0 threats ] [ 0 det ] [ CRIT: 0 ] [ HIGH: 0 ]
// threat_feed
$ sort --newest
Showing all threats

Live intelligence console

Threat level
Fig. 01 · Threat weatherIndexing the archive…
1 square = 1 threat · click to open

Latest Threats