LiteLLM 1.107.0 trojanized on PyPI and Docker images via stolen GitHub tokens: infostealer and RCE backdoor through Python startup hooks
Matéria consolidada. Reúne 6 matérias que o Tifon tinha publicado separadamente sobre a mesma história. A IA reescreveu o relatório com o que as 5 fontes trouxeram em 22/10/2026 00:05; os links antigos trazem para cá.
Fontes: theregister.com ↗ thehackernews.com ↗ wiz.io ↗ aikido.dev ↗ safedep.io ↗
The LiteLLM release 1.107.0 (a widely used open source LLM proxy and AI gateway developed by BerriAI, about 23 million weekly downloads per theregister.com) was trojanized on PyPI on 21 October 2026 and carries a credential stealer (privcollect) plus a remote code execution backdoor. All wheels (Linux, macOS, Windows) drop three extra files in site-packages, two of which run whenever any Python process starts, even one that never imports litellm (safedep.io). The Docker images (GHCR and Docker Hub, tags v1.107.0, latest, main-latest, main-stable) were also trojanized (wiz.io, aikido.dev, theregister.com). The malicious version was uploaded at 11:39 UTC (theregister.com). Aikido published its analysis at about 13:05 UTC, when PyPI had quarantined the version but the Docker image was still live on Docker Hub (aikido.dev). At about 13:40 UTC the GitHub account letters9813 and its repository started returning 404, so the backdoor no longer finds a server address (safedep.io). At about 13:53 UTC the Docker tags were removed (wiz.io). LiteLLM says the release was pushed through three engineers' GitHub accounts, apparently using stolen GitHub CLI OAuth tokens; the initial token theft vector is unknown (thehackernews.com). The malicious code is not in the upstream BerriAI GitHub source. Wiz says it came from commits in a lookalike organization, Berri-AI, that fed the release pipeline (wiz.io), while SafeDep says the cause can only be confirmed from BerriAI's pipeline logs (safedep.io). The same .pth execution behavior was seen in the earlier TeamPCP-linked LiteLLM compromise in March (thehackernews.com), which reportedly exposed more than 2,500 organizations and 434,000 CI/CD pipelines (CloudSEK, via theregister.com). Anyone who installed or pulled this version should treat all reachable credentials as compromised. The last known safe version is v1.106.2 (wiz.io, theregister.com). BerriAI did not respond to The Register (theregister.com).
Detalhes técnicos
- Commits in the lookalike org: on 2026-10-21 between 08:56 and 10:46 UTC the attacker pushed 10 commits to github.com/Berri-AI/litellm using the email [email protected]. The first nine are GitHub-signed and add the persistence files, bump the version and add
data = "cook"to pyproject.toml. A final unsigned commit under [email protected] addsCOPY cook ./cookto the Dockerfiles (wiz.io). - Affected artifacts:
litellm-1.107.0wheels for macOS (x86_64, arm64), manylinux_2_28 (x86_64, aarch64), musllinux_1_2 (x86_64, aarch64) and Windows (win_amd64), plus the sdistlitellm-1.107.0.tar.gz, which has no payload files but a tamperedpyproject.toml(thehackernews.com). - Release abuse: attackers used one user's account to trigger the project-releaser run and another's to approve it (thehackernews.com).
- Injection: the sdist
pyproject.tomlhas one extra line in the maturin section,data = "cook". It copies acook/folder, absent from the sdist and from the source repo, intolitellm-1.107.0.data/purelib/, and pip installs it into site-packages (safedep.io, aikido.dev). No public commit in BerriAI/litellm contains it (safedep.io). - Tag mismatch: tag v1.107.0 (commit 66c8f5b) declares version 1.108.0. The sdist matches a later main commit (a8113b0) plus edited files. The version was reset to 1.107.0 and the companion pins were set to the rc2 values, so a dependency diff against rc2 shows nothing unusual (safedep.io).
- Build provenance: the wheels were built with maturin 1.9.4, like the legitimate releases, with separate native builds on macOS, Linux and Windows. SafeDep checked 539 public GitHub Actions runs and found none that built the release, and PyPI has no provenance attestations for these versions. SafeDep assesses with moderate to high confidence that BerriAI's private release pipeline built the wheels from attacker-modified git source (safedep.io).
- Files dropped:
cook.pth(12 bytes,import cook, runs at every interpreter start),cook.py(the infostealer, a single obfuscated line that decompresses and executes a 61,000-byte payload) andsitecustomize.py(the RAT/backdoor) (aikido.dev). Because the .pth hook fires in every Python process, it covers applications, pip, IDE language servers and CI jobs (safedep.io). Execution happens before LiteLLM is imported (thehackernews.com). - Stealer (internally named privcollect, 16 modules):
- It collects SSH keys, shell history, GPG and TLS keys, and all environment variables, including
/proc/<pid>/environon Linux (aikido.dev, safedep.io). - It collects browser credentials, cookies and history for Chrome, Firefox, Edge and Safari (wiz.io, aikido.dev, theregister.com).
- It collects AWS, Azure and GCP credentials, including
~/.aws/, EC2/ECS IMDS and cloud metadata, GCP service account keys and application default credentials, Azure CLI tokens, plus Docker and Kubernetes secrets (aikido.dev, wiz.io, theregister.com). - It collects CI/CD secrets (GitLab runner, Jenkins, Vault), Git/npm/PyPI credentials and AI developer tool configs (Claude Code, Cursor, Copilot, Windsurf, Gemini CLI and others), including AI tooling credential JSON files (aikido.dev, thehackernews.com).
- It collects API keys for OpenAI, Anthropic, Cohere and other LLM providers (wiz.io, theregister.com).
- On LiteLLM Proxy hosts it dumps LiteLLM_CredentialsTable (via
SELECT * FROM "LiteLLM_CredentialsTable" LIMIT 500) and LiteLLM_ProxyModelTable (wiz.io, aikido.dev).
- It collects SSH keys, shell history, GPG and TLS keys, and all environment variables, including
- Exfiltration: data is encrypted with AES-256-CBC, the key is wrapped with a hardcoded RSA-4096 public key, and the tar.gz is POSTed to
www.litellm[.]dev/healthcheckwith a hardcodedX-Tokenheader (XWiA8gZNa7NcX2XRoAEb) and the User-AgentMozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0)(safedep.io, aikido.dev, wiz.io, theregister.com, thehackernews.com). The marker file/tmp/.pc_once_72129118c59f5636c0bblimits collection to once per host (aikido.dev, wiz.io). - Backdoor (
sitecustomize.py): it takes the lock/tmp/remote_code_loader.lock, then forks and detaches a daemon. Every hour it reads a domain fromdomain.txtin the attacker's GitHub repository (letters9813/pythonclient-test, via raw.githubusercontent.com). It re-runs an embedded stealer copy with no once-per-host marker, then downloads (HTTP GET) andexec()s Python fromhttp://<domain>/codepywith no sandboxing (safedep.io, aikido.dev, thehackernews.com). Wiz says it runs on Linux and macOS only, and that the marker write fails on Windows (wiz.io). - Second stage: Wiz says
domain.txtwas never populated at the time of analysis (wiz.io). SafeDep says hosts whose daemon ran earlier could have received second-stage code, and it could not recover the server address (safedep.io). - Clean artifacts: versions 1.106.2, 1.107.0rc1 and 1.107.0rc2, and the pinned companions litellm-proxy-extras==0.4.110 and litellm-enterprise==0.1.78 (safedep.io).
- Commit visibility: the malicious commits remain visible via the parent repo through fork object sharing (compare a8113b0d...20535d8f) (wiz.io).
- Other analyses: SafeDep, Socket, StepSecurity and Upwind also published reports on this compromise (thehackernews.com).
Remediação
- Identify every host or container that installed
litellm==1.107.0or pulled/ranlitellm/litellm:1.107.0, including thelatest,main-latestandmain-stabletags, and pin to v1.106.2, by digest where possible (wiz.io, aikido.dev, thehackernews.com). - Investigate every environment where Python ran after installation, including proxy containers and CI runners (theregister.com).
- Check for
/tmp/.pc_once_*(exfiltration already fired) and/tmp/remote_code_loader.lock(C2 daemon ran or is running) (aikido.dev). - Hunt for
cook.pth,cook.pyandsitecustomize.pyin site-packages, and for traffic to litellm[.]dev (wiz.io, aikido.dev). - Block the listed domains and the GitHub C2 lookup path (aikido.dev).
- Treat all secrets on affected systems as compromised and rotate them from a clean environment: cloud credentials, LLM provider API keys, keys in the LiteLLM_CredentialsTable, database connection strings, CI/CD secrets, and SSH/GPG/TLS keys (aikido.dev, wiz.io, theregister.com, thehackernews.com).
- Remove the affected version and image, and rebuild affected systems (aikido.dev; the source text is truncated at this point).
- Follow the threat-hunting and mitigation guidance published by Aikido, Wiz and Socket (theregister.com).
- Vendor actions: LiteLLM revoked all involved tokens, removed all but one unaffected user from its GitHub organization, and removed trusted links to its GitHub organization from the public registries. It cannot yet rule out further access to the affected accounts (thehackernews.com).
Relatos divergentes
- Origin of the malicious code: Wiz attributes it to malicious commits in the lookalike organization Berri-AI that fed the release pipeline (wiz.io, repeated by theregister.com). SafeDep says no public commit in BerriAI/litellm contains it and that the exact cause (compromised maintainer or bot credential, private branch or mirror, or the build reference) can only be confirmed from BerriAI's pipeline logs (safedep.io). The most recent account, from LiteLLM itself, says the release was pushed through three engineers' GitHub accounts apparently using stolen GitHub CLI OAuth tokens, with the initial theft vector unknown (thehackernews.com); this is the vendor statement and the most authoritative, and it does not explain the role of the Berri-AI repository.
- Docker image status: Aikido says the Docker image was still live on Docker Hub at the time of its report (aikido.dev), while Wiz says the Docker tags were removed at about 13:53 UTC (wiz.io). Later reports say the malicious images were removed (thehackernews.com, theregister.com), so the images are most likely no longer available.
- Second-stage exposure: Wiz says
domain.txtwas never populated (wiz.io), whereas SafeDep cannot rule out that hosts whose daemon ran earlier received second-stage code (safedep.io).
Linha do tempo
-
LiteLLM PyPI and Docker supply chain compromise (v1.107.0) delivers credential stealer and RAT
ler a análise desta fonte ocultar
Unknown attackers compromised the release process of LiteLLM, the open source AI gateway developed by BerriAI, and distributed malicious version 1.107.0 through PyPI and Docker registries (Docker Hub and GHCR). The package carries an infostealer targeting cloud and AI credentials and a RAT that can execute arbitrary code. PyPI quarantined the version within hours and the Docker image
litellm/litellm:1.107.0was removed, but anyone who ran it should assume their secrets are stolen. LiteLLM gets about 23 million weekly downloads, and the scale of this incident is not yet known. An earlier LiteLLM compromise in March reportedly exposed more than 2,500 organizations and 434,000 CI/CD pipelines (per CloudSEK). BerriAI did not respond to The Register.Technical Details
- The malicious version was uploaded at 11:39 UTC. According to Wiz researchers, the payload came from malicious commits to
github.com/Berri-AI/litellm, a hyphenated lookalike of the legitimate BerriAI organization. This repo was used to inject three malicious files into the release pipeline. cook.pthmakes Python automatically runcook.pyon every interpreter invocation, with no user action.cook.pyis the infostealer, with 16 modules. It harvests browser credentials and cookies (Chrome, Firefox, Edge, Safari), AWS credentials (~/.aws/, environment variables, EC2/ECS IMDS), GCP service account keys and application default credentials, Azure CLI tokens, and API keys for OpenAI, Anthropic, Cohere and other LLM providers. It also takes SSH private keys, GPG keys and shell history.sitecustomize.pyis the RAT. It also runs at interpreter startup and spawns a background daemon that polls attacker infrastructure hourly for commands.- Stolen data is encrypted with AES-256-CBC, the key is wrapped with RSA-4096, and the blob is sent by HTTP POST to
http://www[.]litellm[.]dev/healthcheck. - Host indicators:
/tmp/.pc_once_*means exfiltration has fired;/tmp/remote_code_loader.lockmeans the C2 daemon ran or is still running (Aikido Security). - Affected images also include those pulled via the
latest,main-latestandmain-stabletags.
Remediation
- Stop deploying 1.107.0. The most recent safe version is v1.106.2.
- Investigate every environment where Python ran after installation, including proxy containers and CI runners.
- Check for the two
/tmpartifacts above. - Treat all secrets on affected hosts as compromised and rotate them: LLM provider API keys, cloud credentials, SSH/GPG keys and database connection strings.
- Follow the threat-hunting and mitigation guidance published by Aikido, Wiz and Socket.
- The malicious version was uploaded at 11:39 UTC. According to Wiz researchers, the payload came from malicious commits to
-
LiteLLM 1.107.0 PyPI and Docker Supply Chain Compromise Delivers privcollect Credential Stealer and Backdoor
ler a análise desta fonte ocultar
The widely used LiteLLM Python package was compromised in a software supply chain attack. Malicious version 1.107.0 was published via PyPI wheels and Docker images, delivering a credential stealer and a backdoor, per reports from SafeDep, Socket, StepSecurity and Upwind. LiteLLM says the release was pushed through three engineers' GitHub accounts, apparently using stolen GitHub CLI OAuth tokens. The initial token theft vector is still unknown. The package has been quarantined on PyPI and the malicious Docker images removed. The same
.pthexecution behavior was seen in the earlier TeamPCP-linked LiteLLM compromise in March.Technical Details
- Affected artifacts:
litellm-1.107.0wheels for macOS (x86_64, arm64), manylinux_2_28 (x86_64, aarch64), musllinux_1_2 (x86_64, aarch64) and Windows (win_amd64), plus the sdistlitellm-1.107.0.tar.gz(no payload files, but a tamperedpyproject.toml). - Attackers used one user's account to trigger the project-releaser run and another's to approve it.
- Execution occurs at interpreter start, before LiteLLM is imported, via the path file
cook.pthcontainingimport cook. - Payload 1, a stealer calling itself privcollect, harvests cloud tokens, developer accounts and private keys, AI tooling credential JSON files, Chromium and Firefox browser data, and environment variables. It also targets LiteLLM proxy saved credentials and model configuration.
- Stolen data is packed into a GZIP-compressed TAR and sent by HTTP POST to
litellm[.]dev/healthcheck. - Payload 2 forks a background daemon that checks a GitHub dead drop hourly: it reads
domain.txtingithub[.]com/letters9813, reruns the stealer if a domain is present, then fetches<domain>/codepyvia HTTP GET and executes the response. The repository now returns 404.
Remediation
- Revoke and replace all credentials exposed on systems that installed 1.107.0, working from a clean environment.
- Pin LiteLLM to version 1.106.2 by digest.
- LiteLLM revoked all involved tokens, removed all but one unaffected user from its GitHub organization, and removed trusted links to its GitHub organization from the public registries. It cannot yet rule out further access to the affected accounts.
- Affected artifacts:
-
LiteLLM PyPI package and Docker images trojanized (v1.107.0) with credential stealer and persistence hooks
ler a análise desta fonte ocultar
On October 21, a malicious LiteLLM version (1.107.0) was uploaded to PyPI. Trojanized Docker images on GHCR and Docker Hub (tags v1.107.0, latest, main-latest, main-stable) were also published. The payload was injected through malicious commits in github.com/Berri-AI/litellm, a hyphenated lookalike of the legitimate BerriAI organization, which fed the release pipeline. The package installs a stealer, internally named privcollect, that harvests browser, cloud, developer and AI provider secrets and exfiltrates them to the attacker-controlled domain www.litellm[.]dev. The PyPI version was quarantined and the Docker tags removed at about 13:53 UTC. The last known safe version is v1.106.2.
Technical Details
- Installation drops cook.pth, cook.py and sitecustomize.py into the site-packages root, so the code runs whenever a Python interpreter starts. The .pth file imports
cook, which deobfuscates itself, runs the stealer and writes a marker file at/tmp/.pc_once_72129118c59f5636c0bb. The marker write fails on Windows. - privcollect has 16 modules. It collects Chrome, Firefox, Edge and Safari credentials and cookies, AWS credentials (
~/.aws/, environment variables, EC2/ECS IMDS), GCP service account keys and ADC, Azure CLI token cache, API keys for OpenAI, Anthropic, Cohere and other LLM providers, SSH and GPG keys, and shell history. - On LiteLLM Proxy hosts it queries PostgreSQL directly with
SELECT * FROM "LiteLLM_CredentialsTable" LIMIT 500to dump upstream provider keys. - Data is encrypted with AES-256-CBC (key wrapped with RSA-4096) and sent by HTTP POST to
www.litellm[.]dev/healthcheckwith a hardcoded X-Token header and an Internet Explorer 7 user-agent. - sitecustomize.py runs on Linux and macOS only. It fetches
domain.txtfrom a GitHub dead drop (letters9813/pythonclient-test) and, if populated, downloads and runs a second-stage Python script fromhttp://<domain>/codepy. The file was never populated at the time of analysis, and the repo was taken down. - Between 08:56 and 10:46 UTC the attacker pushed 10 commits using the email [email protected]. The first nine were GitHub-signed, added the persistence files, bumped the version and added
data = "cook"to pyproject.toml so the malware is bundled into the wheel. A final unsigned commit under [email protected] addedCOPY cook ./cookto the Dockerfiles. The commits remain visible via the parent repo through fork object sharing (compare a8113b0d...20535d8f).
Remediation
- Identify any host or container that installed or pulled LiteLLM 1.107.0 or the affected Docker tags, and pin to v1.106.2.
- Search for cook.pth, cook.py, sitecustomize.py and the
/tmp/.pc_once_*marker, and hunt for traffic to litellm[.]dev. - Treat all secrets on affected systems as compromised and rotate them: cloud credentials, LLM provider API keys, keys in the LiteLLM_CredentialsTable, SSH/GPG keys and browser sessions.
- Rebuild affected images and environments from known-good sources.
- Installation drops cook.pth, cook.py and sitecustomize.py into the site-packages root, so the code runs whenever a Python interpreter starts. The .pth file imports
-
LiteLLM 1.107.0 PyPI wheels and Docker image trojanized with infostealer and persistent Python RAT
ler a análise desta fonte ocultar
On October 21, 2026, LiteLLM version 1.107.0, a widely used open source LLM proxy, was found to be compromised. An attacker injected malicious code into the compiled Python wheels published on PyPI, and the official Docker image litellm/litellm:1.107.0 is also affected. The package carries an infostealer that exfiltrates credentials and secrets on first run, and a RAT that lets the attacker execute arbitrary Python on infected hosts every hour. PyPI has quarantined the version, but the Docker image was still live on Docker Hub at the time of reporting. Anyone who installed this version should assume credentials are compromised.
Technical Details
- The attacker abused the
[tool.maturin] data = "cook"directive inpyproject.tomlto bundle acook/directory, which exists only in the compromised build environment and not in the source repo, into every wheel. - Three files are dropped into site-packages:
cook.pth(12 bytes,import cook, runs at every interpreter start),cook.py(the infostealer, a single obfuscated line that decompresses and executes a 61,000-byte payload), andsitecustomize.py(the RAT). - The infostealer collects system information, Chromium and Firefox credentials and history, SSH keys, shell history, AWS/Azure/GCP credentials (including instance metadata endpoints), Docker and Kubernetes secrets, CI/CD secrets (GitLab runner, Jenkins, Vault), AI developer tool configs (Claude Code, Cursor, Copilot, Windsurf, Gemini CLI and others), Git/npm/PyPI credentials, GPG/TLS keys, and all environment variables (including
/proc/<pid>/environon Linux). It also dumps LiteLLM_CredentialsTable and LiteLLM_ProxyModelTable from the LiteLLM database. - Data is encrypted with a hardcoded RSA-4096 public key and sent by HTTP POST to
http://www[.]litellm[.]dev/healthcheck. The sentinel file/tmp/.pc_once_72129118c59f5636c0bblimits it to one run per machine. - The RAT forks a daemon that takes the lock
/tmp/remote_code_loader.lock. Every hour it fetches the current C2 domain fromraw[.]githubusercontent[.]com/letters9813/pythonclient-test/main/domain[.]txt, then downloads andexecs Python fromhttp://{domain}/codepywith no sandboxing. - Network indicators: HTTP POST with User-Agent
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0)and headerX-Token: XWiA8gZNa7NcX2XRoAEb.
Remediation
- Check for
/tmp/.pc_once_*(exfiltration already fired) and/tmp/remote_code_loader.lock(C2 daemon ran or is running) on any host that installedlitellm==1.107.0or ranlitellm/litellm:1.107.0, including thelatest,main-latestandmain-stabletags. - Treat all credentials, API keys, SSH/GPG/TLS keys, cloud and CI/CD secrets reachable from affected hosts as compromised and rotate them.
- Remove the affected version and image, hunt for
cook.pth,cook.pyandsitecustomize.pyin site-packages, and block the listed domains and the GitHub C2 lookup path. - Rebuild affected hosts or containers from known-good sources.
- The attacker abused the
-
Compromised LiteLLM 1.107.0 on PyPI Drops Credential Stealer and Remote Code Backdoor via Python Startup Hooks
ler a análise desta fonte ocultar
The LiteLLM 1.107.0 release on PyPI was trojanized with a credential stealer and a remote code execution backdoor. All seven wheels (Linux, macOS, Windows) install three extra files in site-packages, and two of them run whenever any Python process starts, even one that never imports litellm. The malicious code is not in the upstream GitHub source, and PyPI has since removed the release. SafeDep assesses with moderate to high confidence that BerriAI's private release pipeline built the wheels from attacker-modified git source. The exact cause (compromised maintainer or bot credential, private branch or mirror, or the build reference) can only be confirmed from BerriAI's pipeline logs. Versions 1.106.2, 1.107.0rc1 and 1.107.0rc2 are clean, as are the pinned companion packages litellm-proxy-extras==0.4.110 and litellm-enterprise==0.1.78.
Technical Details
- Injection: the sdist
pyproject.tomlhas one extra line in the maturin section,data = "cook". It copies acook/folder (absent from the sdist) intolitellm-1.107.0.data/purelib/, and pip installs it into site-packages. No public commit in BerriAI/litellm contains it. - Tag mismatch: tag v1.107.0 (commit 66c8f5b) declares version 1.108.0. The sdist matches a later main commit (a8113b0) plus edited files. The version was reset to 1.107.0 and the companion pins were set to the rc2 values, so a dependency diff against rc2 shows nothing unusual.
- Build provenance: the wheels were built with maturin 1.9.4, like the legitimate releases, with separate native builds on macOS, Linux and Windows. SafeDep checked 539 public GitHub Actions runs and found none that built the release, and PyPI has no provenance attestations for these versions.
- Payload 1,
cook.pth/cook.py:cook.pthcontainsimport cook, so the stealer runs in every Python process (applications, pip, IDE language servers, CI jobs). The zlib/base64-packed code collects SSH keys, cloud credentials, CI/CD secrets, AI tool tokens, browser passwords and history, shell history, GPG keys, TLS private keys, cloud metadata and the LLM provider keys in a LiteLLM proxy database. Results are encrypted with AES-256-CBC, the key is wrapped with RSA-OAEP (RSA-4096), and the tar.gz is POSTed towww.litellm[.]dev/healthcheckwith anX-Tokenheader. A marker file limits collection to once per host. - Payload 2,
sitecustomize.py: it takes a lock file, forks and detaches a daemon, and every hour reads a domain fromdomain.txtin the attacker's GitHub repository, re-runs an embedded stealer copy with no once-per-host marker, and downloads andexec()s code fromhttp://<domain>/codepy. - Takedown: at 13:40 UTC on 2026-10-21 the GitHub account letters9813 and its repository returned 404, so the backdoor currently finds no server address. Hosts whose daemon ran earlier could have received second-stage code. SafeDep could not recover the server address.
Remediation
- Check for litellm==1.107.0 in environments, lockfiles, containers and CI caches. Treat any host that installed it as compromised.
- Look for
cook.pth,cook.pyandsitecustomize.pyin site-packages,/tmp/.pc_once_72129118c59f5636c0bb,/tmp/remote_code_loader.lock, and traffic to litellm[.]dev. - Rotate all credentials reachable from affected hosts: SSH keys, cloud and CI/CD secrets, AI tool tokens, LLM provider keys and browser-stored passwords.
- Because second-stage code may have run, consider rebuilding affected hosts. Pin known-good versions (1.106.2 or 1.107.0rc2).
- Injection: the sdist