Security (Updated September 17, 2026) 17 min read

LiteLLM's PyPI Backdoor: What It Means for the AI Skill Supply Chain

TeamPCP pushed a credential stealer into litellm 1.82.7 and 1.82.8 on PyPI via a compromised Trivy action. What it did, and why AI skills are next.

On March 24, 2026, LiteLLM 1.82.7 and 1.82.8 reached PyPI carrying a multi-stage credential stealer and a .pth startup backdoor. The threat actor TeamPCP got in through a compromised Trivy GitHub Action, not the repository. LiteLLM’s security advisory tells anyone who installed either version to assume total credential compromise.

Updated September 2026: the assume-compromise guidance is unchanged. LiteLLM’s advisory was still marked as an active investigation on March 27, 2026, and no source has since narrowed the exposure window below the 40-minute figure the project published.

“Treat any credentials present on the affected systems as compromised, including: API keys, Cloud access keys, Database passwords, SSH keys, Kubernetes tokens, Any secrets stored in environment variables or configuration files”

— LiteLLM security update, March 2026

This was not a rogue maintainer or a typosquat. It was a CI/CD pipeline compromise, and Wiz traced the entry point to “an API token exposed via the prior Trivy incident” — the same campaign that had already hit Aqua Security’s Trivy scanner and Checkmarx’s KICS GitHub Action in the days before. The LiteLLM incident is the highest-impact link in that chain.

This post examines the technical details, draws a direct line from PyPI package attacks to the emerging AI skill supply chain, and explains what SkillSafe’s model would have caught.

Key Figures

FigureWhat it measuresSource
1.82.7, 1.82.8Backdoored litellm versions published to PyPILiteLLM advisory
~95 millionlitellm downloads per monthCyberInsider
~3 millionlitellm downloads per daySonatype
10:39 UTC, March 24When the project says the packages went liveLiteLLM advisory
~40 minutesExposure window, per LiteLLM’s own advisoryLiteLLM advisory
08:30 -> 11:25 UTCPublication to PyPI quarantine, per Wiz (~3 hours)Wiz
”at least two hours”Exposure window, per SonatypeSonatype
13 minutesGap between the two malicious releasesLiteLLM advisory
35 tagsCheckmarx KICS action tags hijacked on March 23, 12:58-16:50 UTCWiz
3 stagesCredential sweep, Kubernetes lateral movement, systemd persistenceSonatype
2 domainsExfiltration: checkmarx[.]zone (1.82.7), models[.]litellm[.]cloud (1.82.8)Wiz
1,184 skillsMalicious AI skills in the comparable ClawHavoc campaignSkillSafe

Rows 5 to 7 disagree, and the affected project publishes the smallest number — the direction of bias you would expect. Treat the whole of March 24 as suspect when you audit build logs.

What Happened

Timeline of the TeamPCP campaign: Aqua Security's Trivy scanner compromised first, 35 Checkmarx KICS action tags hijacked on March 23, litellm 1.82.7 and 1.82.8 published on March 24, PyPI quarantine the same morning, investigation still active on March 27

Figure: one stolen CI token propagated across three separate vendors. Each compromise supplied the credential for the next.

The Attack Chain

TeamPCP did not compromise LiteLLM’s repository directly. They compromised a dependency in LiteLLM’s CI/CD pipeline — specifically, a Trivy GitHub Action used for security scanning. The irony is worth noting: the security scanner itself became the attack vector.

OWASP’s CI/CD Security Cheat Sheet names the mitigation this defeats: “Version pinning should be performed… and the integrity of any package the system downloads should be validated by comparing its hash or checksum to a known good hash of the pinned package.” An action referenced by a mutable tag is an unpinned dependency with read access to your secrets.

Through the compromised Trivy action, TeamPCP obtained PyPI publishing credentials from LiteLLM’s CI environment. With those credentials, they published two backdoored versions in quick succession:

  • v1.82.7 at 10:39 UTC — malicious payload injected into proxy_server.py, exfiltrating to checkmarx[.]zone
  • v1.82.8 at 10:52 UTC — added litellm_init.pth alongside the proxy_server.py payload, exfiltrating to models[.]litellm[.]cloud

The .pth file is the more dangerous mechanism. Per Python’s site module documentation, a line in a .pth file beginning with import is executed at interpreter startup — not when litellm is imported, but whenever any Python process starts in an environment where litellm is installed. The payload was double base64-encoded and launched via subprocess, bypassing simple inspection.

Attack chain: a compromised Trivy action yields a PyPI token, which publishes backdoored litellm versions, whose .pth file runs on every Python start and triggers a credential sweep, Kubernetes lateral movement and a systemd backdoor

Figure: the .pth file is the pivot. It converts “installed once” into “executes on every Python process,” which is why LiteLLM’s guidance is to assume every secret on the host is gone.

The Payload: Three Stages

Once triggered, the malware executed a three-stage attack (Sonatype, Wiz):

Stage 1: Credential Harvesting. The payload swept the host for every credential it could find:

  • SSH keys (~/.ssh/)
  • AWS, GCP, and Azure credentials
  • Kubernetes configs and service account tokens
  • CI/CD secrets and Docker configs
  • .env files, .gitconfig, and shell history
  • Database connection strings
  • Cryptocurrency wallet files and seed phrases

Stage 2: Kubernetes Lateral Movement. On machines with cluster access, the malware deployed privileged pods to every reachable node — turning one compromised developer machine into a foothold across the organization’s infrastructure.

Stage 3: Persistent Backdoor. A systemd service was installed that polled attacker-controlled infrastructure for additional binaries, ensuring persistence even if the malicious litellm version was later uninstalled.

Stolen data was bundled into an encrypted archive (tpcp.tar.gz) and exfiltrated to models.litellm.cloud, a domain controlled by the attackers (The Hacker News).

The Blast Radius

Sonatype puts litellm at three million downloads per day; the 95-million-monthly figure implies roughly 3.4 million. Against that rate, even the most conservative published window — the project’s own 40 minutes — is thousands of installs, and CI/CD caching and mirrors widen it. LiteLLM’s advisory attempts no install count; it tells anyone who pulled either version to assume full credential compromise, the only defensible position when the payload runs on every interpreter start.

Why This Matters for AI Skills

The LiteLLM attack targeted a Python package. AI coding skills — .md instruction files used by Claude Code, Cursor, Windsurf, and similar tools — are a different artifact type. But the underlying supply chain dynamics are identical, and in several ways the skill attack surface is worse.

Same Vectors, Higher Privilege

A Python package executes in a sandboxed interpreter with whatever permissions the calling code grants. An AI skill executes inside an agent that typically has:

  • Full filesystem read/write access to the project directory (and often the home directory)
  • Shell command execution
  • Network access
  • Access to environment variables, SSH keys, and credential files

When a developer installs a malicious Python package, the damage depends on what the package can reach. When a developer installs a malicious AI skill, the agent becomes the attacker — with the developer’s full environmental access. The same reasoning drives our MCP security guidance: capability, not artifact type, decides blast radius.

The ClawHavoc campaign demonstrated this in January 2026: 1,184 malicious skills delivered credential-stealing malware through nothing more than carefully written .md instructions that directed the AI agent to download and execute external binaries, read credential files, and persist via agent memory files.

CI/CD Compromise Maps Directly to Skill Registries

TeamPCP’s method — compromising a CI/CD dependency to steal publishing credentials — applies equally to any registry that relies on long-lived publishing tokens. PyPI’s own mitigation for this class is Trusted Publishing, which replaces a stored API token with a short-lived OIDC exchange, and SLSA formalizes the provenance ladder above it. Neither existed as a requirement in LiteLLM’s release path on March 24.

If an attacker steals a skill publisher’s API key through a compromised GitHub Action, a leaked .env file, or a phishing attack, they can publish a backdoored version of any skill that publisher maintains. The LiteLLM incident proves this is not theoretical: TeamPCP executed it against one of the most popular packages in the Python ecosystem. Skill registries that store publishing credentials the same way are vulnerable to the same attack.

The .pth Trick Has a Skill Equivalent

The .pth mechanism — code that executes on interpreter startup regardless of whether the package is explicitly imported — has a direct parallel in AI skills. Skills can modify agent configuration files (CLAUDE.md, SOUL.md, MEMORY.md) to inject instructions that persist across sessions and execute in every future interaction, not just when the skill is active.

This was one of ClawHavoc’s most effective techniques. The LiteLLM attack shows the same principle — parasitic persistence via a platform mechanism designed for convenience — applied at the package level. Both exploit the same architectural assumption: that installed components are trustworthy.

What SkillSafe’s Model Catches

SkillSafe cannot prevent a CI/CD pipeline compromise at LiteLLM or any other upstream project. What it can prevent is the same class of attack succeeding in the AI skill supply chain. The defense is layered: pre-share scanning blocks malicious content, cryptographic verification catches tampering, audit logging provides forensic visibility, publish rate limits constrain blast radius, and emergency key revocation enables instant incident response.

Pre-Share Scanning Gates Distribution

Every skill on SkillSafe must pass a security scan before a share link can be created. This is not a post-publish check — sharing is blocked until the scan completes with a non-critical verdict.

If the LiteLLM attack vectors were translated to a skill, the following rules from the SkillSafe scanner ruleset v2026.03.15 would trigger:

LiteLLM Attack VectorSkillSafe Scanner Rule(s)Result
Double base64-encoded payloadSS05 b64_decode_exec / b64_file_exec: base64 decode-and-execute pipelines (critical)Blocked
Credential file harvesting (~/.ssh/, .env)SS17 cred_read_aws, cred_read_docker, cred_find_dirs: credential file access patterns (critical/high)Blocked
Exfiltration to external domainSS03 shell_exfil_service: outbound HTTP to known exfil services (high) + SS-CP cp01_exec_plus_network: process execution combined with network calls (critical)Blocked
curl | sh equivalent binary downloadSS01 py_subprocess_run / py_os_system: shell command execution (high) + SS-CP cp01_exec_plus_network (critical)Blocked
Kubernetes lateral movement commandsSS01 py_subprocess_run / py_subprocess_popen: subprocess spawning (high)Blocked
Persistence via config file modificationSS04 agent_memory_write / agent_memory_inject: shell writes to CLAUDE.md, SOUL.md, MEMORY.md (high)Blocked
Rapid-fire publishing with stolen credentialsPer-account daily publish limits (50/200/1000 by tier)Rate-limited
Stolen key used from unknown IPAudit log captures IP, user agent, timestamp per save/shareDetected
Delayed discovery of credential theftEmergency key revocation (DELETE /v1/account/keys)Instant response

A skill implementing any of LiteLLM’s payload stages would fail the pre-share scan. It could be saved privately (saving is unrestricted) but could never reach other users through the registry. Even if a skill somehow evaded content scanning, the operational security layers — publish rate limits, audit trails, and emergency revocation — constrain and expose the attack.

Cryptographic Tamper Detection Defeats Credential Theft

TeamPCP’s core strategy was stealing publishing credentials to push modified versions of a legitimate package. In SkillSafe’s model, even if an attacker steals a publisher’s API key and pushes a backdoored skill version:

  1. The new version must pass a pre-share scan (which the malicious content would fail)
  2. Even if the scan were somehow bypassed, the consumer’s client re-scans on download and computes an independent tree hash
  3. The server compares both scan reports and tree hashes — any discrepancy produces a critical verdict

The attacker would need to compromise the publisher’s credentials, bypass the pre-share scan, and prevent the consumer’s client from detecting the modification. Each layer is independent. Defeating one does not weaken the others.

Namespace Verification Raises the Bar

LiteLLM is a single package name on PyPI. Anyone with PyPI credentials can publish to it. SkillSafe’s namespace model (@publisher/skill-name) means an attacker needs to compromise the specific publisher account, not just any publishing credential. Combined with email verification requirements for sharing, the attack surface for credential-based publishing attacks is narrower.

Publish Audit Trail

Every skill save and share on SkillSafe is recorded in a structured audit log — capturing the account, action, IP address, user agent, and timestamp. If a compromised key were used to publish a backdoored version, the forensic trail is immediate: which key, from which IP, at what time.

PyPI had no equivalent during the LiteLLM incident. Investigators had to reconstruct the timeline from package metadata and external logs — which is exactly why three vendors publish three different exposure windows for the same morning. An integrated audit trail turns “what happened?” from a multi-day forensic exercise into a single database query.

Per-Account Daily Publish Limits

TeamPCP published two malicious versions within 13 minutes. SkillSafe enforces per-account daily publish limits (50 versions/day on free tier, 200 on paid, 1,000 on enterprise) as a defense-in-depth measure against credential-based spam attacks. A stolen key can’t be used to flood the registry with hundreds of backdoored versions across multiple skill names — the account-level budget constrains the blast radius even if the key is compromised.

Emergency Key Revocation

When LiteLLM’s team discovered the compromise, their immediate priority was revoking the stolen PyPI credentials. SkillSafe provides a one-call panic button (DELETE /v1/account/keys) that atomically revokes every active API key on an account. If a publisher suspects credential theft, they can kill all access in a single request — no need to enumerate and revoke keys one by one while the attacker continues publishing.

Lessons from the LiteLLM Incident

1. CI/CD Pipelines Are the New Attack Surface

TeamPCP didn’t hack LiteLLM’s code. They hacked the tool that checks LiteLLM’s code, then used the token it leaked. This is a pattern: as direct code compromise gets harder, attackers move upstream to the build and release infrastructure. The KICS stage makes the shape explicit — 35 tags hijacked inside a four-hour window on March 23, which is a scripted operation, not a manual one.

For skill publishers, this means: your publishing credentials are as sensitive as your production database credentials. Prefer short-lived, workload-identity credentials (PyPI Trusted Publishing is the model) over stored tokens, keep them out of CI environment variables that any third-party action can read, and audit every GitHub Action and CI plugin in your pipeline.

2. Reactive Scanning Cannot Catch Zero-Day Payloads

PyPI quarantined the malicious versions the same morning — a fast response by any standard, and Sonatype says its own tooling blocked the versions “within seconds of publication” for its customers. But even 40 minutes at three million downloads per day is a real exposure window, and reactive models (scan after publish, quarantine after detection) will always have this gap.

Pre-share scanning inverts the model: the skill cannot reach consumers until it passes. The window between “malicious code exists” and “malicious code is distributed” is zero, because distribution is gated on the scan. That is the difference our scanning architecture comparison walks through in detail.

3. The .pth / SOUL.md Pattern Is Becoming Standard

Both the LiteLLM attack and ClawHavoc used platform-native persistence mechanisms — .pth files for Python, SOUL.md / MEMORY.md injection for AI agents — to maintain access after the initial payload. These mechanisms are designed for legitimate use and are rarely inspected.

Security models need explicit rules for these persistence vectors. Signature-based detection will always lag behind novel payloads, but behavioral rules (“does this skill write to agent configuration files?”) catch the pattern regardless of the specific payload.

4. Credential Rotation Is Not Optional

LiteLLM’s advisory instructs affected users to assume full compromise. This is the correct guidance. If the LiteLLM credential stealer ran on your machine — even briefly — every secret on that machine should be considered exfiltrated. Rotate SSH keys, cloud credentials, API tokens, database passwords, and browser sessions.

The same applies retroactively to ClawHavoc. If you installed unverified skills during January-March 2026, a precautionary credential rotation is warranted.

What to Do Now

If you use LiteLLM: Check whether v1.82.7 or v1.82.8 was installed in any of your environments. pip show litellm shows the currently installed version. Because the published exposure windows disagree — 40 minutes per LiteLLM, ~3 hours per Wiz — audit CI/CD logs and Docker image build histories for any litellm install on March 24, 2026, not just a narrow slice of it. If either version was installed, follow LiteLLM’s remediation guidance and hunt for the two exfiltration domains at your network egress.

If you publish AI skills on SkillSafe: Audit your CI/CD pipeline for credential exposure. Verify that publishing tokens are stored in secrets managers, not in environment variables accessible to third-party actions. If you suspect a key has been compromised, use the emergency revoke-all endpoint (DELETE /v1/account/keys) to kill all active keys instantly, then check your audit log for unexpected publish activity. Review the daily publish limits for your tier — unusual volume against these limits can be an early indicator of compromise.

If you install AI skills: Use a registry that scans before distribution and verifies integrity at install time. If your current registry doesn’t provide pre-install scan reports, run any GitHub-hosted skill through the SkillSafe web scanner before activating it — no account required. More incidents in the same shape: /blog/tag/supply-chain/.

Frequently Asked Questions

How do I check whether I installed a backdoored litellm version?

Run pip show litellm for the current version, then grep your CI logs, lockfiles and Docker build history for 1.82.7 or 1.82.8 on March 24, 2026. Also look for a litellm_init.pth in your site-packages directory and for outbound traffic to checkmarx[.]zone or models[.]litellm[.]cloud.

Why is a Python .pth file more dangerous than a malicious import?

Because it does not need the package to be imported. Python’s site documentation specifies that .pth lines starting with import execute at interpreter startup, so every Python process in that environment runs the payload — cron jobs, test runners, unrelated scripts. That is why LiteLLM’s advisory treats the whole host as compromised.

Was the malicious package really only live for 40 minutes?

The three published figures disagree: LiteLLM says about 40 minutes from 10:39 UTC, Sonatype says “at least two hours,” and Wiz reconstructs publication at 08:30 UTC with PyPI quarantining at 11:25 UTC — roughly three hours. At three million downloads a day, the difference matters, so audit the full day rather than a window.

Can the same attack hit an AI skill registry?

Yes, and more cheaply. A skill is instructions an agent executes with the developer’s filesystem, shell and network access, so it needs no .pth trick. ClawHavoc shipped 1,184 malicious skills in January 2026 using plain .md files. Gating distribution on a passing scan is what removes the publish-then-detect window.

Who is TeamPCP and what else have they compromised?

TeamPCP is the group Wiz and Sonatype attribute this campaign to. Before LiteLLM they compromised Aqua Security’s Trivy scanner and hijacked 35 tags of Checkmarx’s KICS GitHub Action between 12:58 and 16:50 UTC on March 23, 2026. The Trivy compromise is what leaked the token used against LiteLLM.

Sources

SkillSafe did not independently verify all reported figures. We cite published security research from the sources listed above.