Email me

AI · · 11 min read · Matt Busel

Filed under LLMs AI agents Guides

LiteLLM got backdoored again. Check if it took your keys in 5 min

LiteLLM got backdoored again. Check if it took your keys in 5 min
On this page · 12 sections
  1. What happened, in 2 hours
  2. The 5-minute check (don't run pip first)
  3. 20 of 30 AI frameworks would have let it in
  4. Twice in 7 months, and the second time after "hardening"
  5. LiteLLM blamed Claude Code. I checked 1,193 transcripts
  6. Railway, same day, same target
  7. The 15-minute rotation order
  8. What it wanted from a normal dev box
  9. The worst take of the day
  10. The numbers so far
  11. My bet, and your turn
  12. Rotate every key it touched, in order, tonight

TL;DR: You can find out in 5 minutes whether today's LiteLLM backdoor (or Railway's leak) touched your machine, and rotate what it could have taken in about 15. The commands and the order are below. Why it matters: for 1 hour 43 minutes this morning, pip install litellm handed you a credential stealer, and I checked 76 popular AI packages against the versions they had live at that moment. 20 of the 30 that use LiteLLM would have accepted it.

This is the second time in 7 months. LiteLLM's own status update now blames tokens that Claude Code put into responses. So I scanned 1,193 of our own Claude Code transcripts for GitHub tokens. I found 0. My read: the hole wasn't Claude Code. It was a logging proxy sitting on the open internet.

Animated bar chart: 20 of 30 AI packages that use LiteLLM accepted the backdoored 1.107.0, as published at 7:39 AM ET Oct 21 2026. Top 14 by monthly downloads: strands-agents 37.1M accepts via an extra, openai-agents 12.4M via an extra, mini-swe-agent 11.6M accepts on a plain install, google-adk 10.1M via an extra, instructor 8.5M blocked, openhands-sdk 5.5M blocked, dspy 5.3M accepts, crewai 2.4M via an extra, mem0ai 2.0M blocked, agno 1.8M via an extra, opik 1.7M blocked, langchain-litellm 1.1M accepts, lm-eval 1.0M blocked, weave 0.8M via an extra.
Our scan: PyPI metadata of the release each of 76 AI packages had live at 11:39 UTC Oct 21 2026, read 7:50 PM ET; downloads from pypistats.org, last 30 days. Static frame: hero.png.

What happened, in 2 hours

All times ET, Oct 21 2026, from LiteLLM's incident post, GitHub issue #47826 and SafeDep's teardown:

  • 7:39 AM: litellm==1.107.0 lands on PyPI, all seven wheels, Linux, macOS and Windows.
  • 7:46 AM: the Docker tags v1.107.0, latest, main-latest and main-stable start pointing at the same poisoned image.
  • 8:22 AM: JFrog flags it. Socket follows at 10:03 AM.
  • 9:23 AM: PyPI pulls the release. Docker Hub stays poisoned until 10:20 AM.
  • 3:14 PM: Wiz tells LiteLLM it has started to see post-exploitation activity.
  • 5:22 PM: LiteLLM posts the attack chain and points at Claude Code.
  • 6:05 PM: a different fire. "Railway has been hacked." More on that below.
Two screenshots. JFrog Security, @JFrogSecurity, Oct 21 2026 8:22 AM ET: JFrog Security Research has identified a supply-chain attack involving malicious code in the LiteLLM 1.107.0 PyPI release. Avoid this version and investigate environments where it was installed or executed. 260.6K views. Below it Socket, @SocketSecurity, 10:03 AM ET: LiteLLM, a Python package for connecting to AI model providers with 92M+ monthly downloads, has been compromised. Version 1.107.0 ships credential-stealing malware through PyPI wheels and Docker images. 216.8K views.
@JFrogSecurity and @SocketSecurity on X, Oct 21 2026, captured 7:34 PM ET Oct 21 2026, real and unedited.

Plain English for what the package did. A .pth file is a tiny file Python reads every time it starts. The bad wheel dropped one called cook.pth that runs a stealer, plus a sitecustomize.py that starts a background process and phones home every hour for new code. You didn't have to import LiteLLM. If any Python process started on that machine, the stealer ran: your app, your IDE's language server, your CI job, even pip itself.

The 5-minute check (don't run pip first)

LiteLLM's own incident page says "You can check with pip show litellm". The same page, a few lines later, says any Python start in an affected environment runs the stealer again, "and that includes running pip." So don't. Check from the shell first. None of these commands start Python.

# 1. Is the bad version or its implant anywhere on this machine?
find / -path /proc -prune -o \( -name 'cook.pth' -o -name 'litellm-1.107.0.dist-info' \) -print 2>/dev/null
find / -path /proc -prune -o -path '*site-packages/sitecustomize.py' -size 25509c -print 2>/dev/null

# 2. Did it already run? (the stealer's marker and the backdoor's lock file)
ls -la /tmp/.pc_once_72129118c59f5636c0bb /tmp/remote_code_loader.lock 2>/dev/null

# 3. Lockfiles and requirements that pinned or resolved to it
grep -rnE 'litellm[^0-9]*1\.107\.0' --include='*.lock' --include='requirements*.txt' --include='pyproject.toml' . 2>/dev/null

# 4. Docker: the poisoned image index starts with sha256:1bbcb1443bc9
docker images --digests | grep -i litellm

On Windows, run this in PowerShell instead of step 1:

Get-ChildItem C:\ -Recurse -Force -ErrorAction SilentlyContinue -Include cook.pth,litellm-1.107.0.dist-info | Select-Object FullName

Then two questions only you can answer. Did any CI job, Dockerfile or fresh venv install LiteLLM without an exact pin between 7:39 and 9:23 AM ET? Did anything pull litellm/litellm:latest or main-stable between 7:46 and 10:20 AM ET? If yes to either, treat that machine as compromised, even if step 2 finds nothing. LiteLLM says it plainly: containers and tmp cleanup remove the marker, so a clean result proves nothing.

How big was that window? At yesterday's pace, LiteLLM got 3,650,152 downloads in a day, about 152,000 an hour. Not all of those resolve to the newest version. A lot of them do.

20 of 30 AI frameworks would have let it in

This is the experiment I ran tonight. I took 76 popular AI and agent packages on PyPI. For each one I found the release that was live at 7:39 AM ET, the minute the bad wheel went up, and read its declared LiteLLM requirement. Then I asked one question: does that range include 1.107.0?

  • 30 of the 76 depend on LiteLLM.
  • 8 accept 1.107.0 on a plain install: mini-swe-agent, dspy, langchain-litellm, guardrails-ai, llama-index-llms-litellm, gpt-researcher, open-interpreter and praisonai.
  • 12 more accept it through an optional extra, like pip install "crewai[litellm]": strands-agents, openai-agents, google-adk, crewai, agno, smolagents and six others.
  • 10 block it, only 3 of them with an exact pin.

The most-downloaded one is the best story. strands-agents does 37.1M downloads a month. At 7:39 AM its [litellm] extra allowed anything under 2.0. At 2:47 PM ET it shipped a new release capped at <1.107.0, seven hours after the fire started.

Three ways to depend on LiteLLM and what each did on Oct 21 2026. mini-swe-agent, 11.6M downloads a month, requires litellm not 1.82.7, not 1.82.8, at least 1.75.5: it blocklists March's two bad versions and accepted 1.107.0. openhands-sdk, 5.5M a month, requires litellm below 1.106: an upper bound shipped Oct 19, blocked. aider-chat requires exactly litellm 1.81.10: blocked.
Specs: the PyPI release each package had live at 11:39 UTC Oct 21 2026, read 7:50 PM ET; downloads from pypistats.org.

And here's the part that should make every maintainer wince. mini-swe-agent (11.6M downloads a month) learned from March. Its requirement says litellm!=1.82.7,!=1.82.8,>=1.75.5, which excludes the two versions backdoored last time by name. That blocklist let today's backdoor straight in. A blocklist only protects you from the last attack. The packages that were safe today were safe because of an upper bound or an exact pin, not because anyone remembered March.

Twice in 7 months, and the second time after "hardening"

On March 24 2026, versions 1.82.7 and 1.82.8 shipped a stealer through a compromised maintainer account and the CI pipeline. Version 1.82.8 used a file called litellm_init.pth. Same trick, same package, same targets.

Comparison table, LiteLLM on PyPI seven months apart. March 24 2026: bad versions 1.82.7 and 1.82.8, trick litellm_init.pth, runs when any Python starts, way in a maintainer account and the CI pipeline, live 40 minutes to about 3 hours, fix promised a new isolated pipeline. October 21 2026: bad version 1.107.0 plus Docker latest, trick cook.pth plus sitecustomize.py, runs when any Python starts, way in three engineers' GitHub CLI tokens and the private release workflow, live 1 hour 43 minutes on PyPI, post-mortem pending.
March: NetSPI, Snyk and LiteLLM's update. October: LiteLLM's incident post, GitHub issue #47826 and SafeDep, all read 7:30 PM ET Oct 21 2026.

LiteLLM's 5:22 PM update says that after March it "meaningfully hardened" the release pipeline: a private release repo, Trusted Publishers, immutable Docker tags, signed images, and publishing locked to "an account locked to a specific laptop physically located within our office." Then, by its own account, it widened release permissions on Monday for daily backports. The attacker had GitHub CLI tokens for three engineers, one of them an organization owner, disabled branch protection, force-pushed a change to the release workflow and pointed it at a lookalike repo, Berri-AI/litellm. The signed, official pipeline then signed and shipped the malware.

That's the lesson nobody wants to hear. Signing proves the package came out of your pipeline. It doesn't prove your pipeline was still yours.

LiteLLM blamed Claude Code. I checked 1,193 transcripts

Word for word from the status update: "we have observed specific situations in which Claude Code will embed a user's GitHub CLI OAuth token into a response body, and in situations where response bodies are logged, these tokens may appear in LiteLLM logs." They believe the attacker got into an internal LiteLLM deployment "exposed to the public internet," read the tokens out of its logs, and used them on the release workflow.

Our agent team runs on Claude Code, so I tested it on our own box. Every prompt, tool call and tool result Claude Code has seen here is in ~/.claude/projects: 1,193 transcript files, 3.1 GB. I counted credential-shaped strings with regexes and never printed a value.

Stat card: LiteLLM blamed Claude Code, so we checked ours. 1,193 Claude Code transcript files on our dev box, 3.1 GB of prompts, tool calls and tool output scanned. 0 GitHub CLI tokens or personal access tokens. 0 Anthropic or OpenAI API keys. 2 AWS-key-shaped strings, one of them Amazon's documentation example.
Our run, 7:33 to 7:40 PM ET Oct 21 2026, regex counts only, values never printed. Claim tested: LiteLLM's 21:22 UTC update on GitHub issue #47826.

Zero GitHub CLI tokens. Zero personal access tokens. Zero Anthropic or OpenAI keys. Two AWS-key-shaped strings, and one of those is Amazon's own documentation example. So in our logs, the thing LiteLLM describes never happened once.

I'm not saying it can't happen. If you ask an agent to run gh auth token, the token is in the response, and every proxy that logs response bodies now has it. But "Claude Code embedded a token" is the least interesting sentence in that update. The interesting one is that an AI gateway holding full response bodies was reachable from the internet. LiteLLM sells that gateway. Logging every prompt and response is a feature people turn on for cost tracking and debugging. My read: tonight a lot of teams are finding out their LLM logs are the juiciest credential store they own.

Railway, same day, same target

At 6:10 PM ET Railway's status page linked a security notice: an unauthorized party "may have accessed encrypted environment variables and, for some of them, obtained the decrypted contents." Then this line: "We believe this is part of a series of attacks recently targeting platform companies with the aim of compromising AI inference providers."

Screenshot of a post by Andrew Curran, @AndrewCurran_, Oct 21 2026 6:05 PM ET: Railway has been hacked. 103.7K views.
@AndrewCurran_ on X, Oct 21 2026, captured 7:34 PM ET Oct 21 2026, real and unedited.

Read that twice. The target in both of today's stories is the same thing: the keys that buy AI inference. There's a name for reselling stolen AI keys, LLMjacking, and the reason is simple. A stolen database password needs work to turn into money. A stolen model key is money the minute someone sends a request on your bill. Look at the stealer's own module list: there's a module just for AI tools (Claude Code, Codex, Cursor, Gemini CLI, Copilot, Hugging Face) and one that dumps the provider keys out of a LiteLLM proxy database.

Railway users have it worse tonight. Builds are paused, so you can't redeploy with new keys. One user posted that his leaked keys were being used and he couldn't swap them. The fix is ugly but it works: revoke the key at the provider anyway. Your app breaks until builds come back. The bleeding stops now.

The 15-minute rotation order

If the check above says you were exposed, or you're on Railway, rotate in this order. It's sorted by how fast each secret turns into damage.

  1. AI provider keys (OpenAI, Anthropic, OpenRouter, Bedrock, Vertex). They're cash within minutes. Revoke, reissue, and set a hard monthly spend cap while you're in the dashboard. Then check usage since 7:39 AM ET.
  2. Anything that can publish code: GitHub (revoke the "GitHub CLI" app under Settings, Applications, Authorized OAuth Apps, plus PATs and deploy keys), PyPI, npm and crates.io tokens. This is how today's attack spread. Don't be the next one.
  3. Cloud credentials: AWS keys and instance roles (the stealer reads the instance metadata service), gcloud, Azure, kubeconfig.
  4. Payments: Stripe and anything with a live key.
  5. Databases: every DATABASE_URL, especially a LiteLLM proxy database.
  6. SSH keys: remove them from GitHub and your servers, then make new ones.
  7. Your browser's saved passwords: the stealer decrypts Chrome's and reads Firefox's. Email first, then anything with money in it.

Then rebuild the affected venvs and images from scratch, pinned to litellm==1.106.2 or older.

What it wanted from a normal dev box

LiteLLM isn't installed on our machine, and there are 0 implant files in the 5 Python environments we found on it. But I wanted to know what this stealer would have found if it had run here. So I checked its target list against our dev box, existence only, nothing opened.

Card: the stealer's shopping list versus one real dev box. 10 of 23 places it looks were present on ours, plus 9 .env files in top-level project folders; LiteLLM itself not installed, 0 implant files. Target groups: AI tools (Claude Code, Claude Desktop, Codex auth.json, Cursor, Gemini CLI, VS Code mcp.json, Hugging Face token), code and publish tokens (gh CLI, git credentials, SSH keys, npm, PyPI, crates.io), cloud and infra (AWS, gcloud, Azure, Docker, Kubernetes, Vault, Terraform, .env files), and you (Chrome and Firefox saved passwords, shell and PowerShell history).
Our run, 7:40 PM ET Oct 21 2026, file existence only. Target list from the stealer config decoded by SafeDep and in GitHub issue #47826.

10 of 23 places it looks were full, plus 9 .env files sitting in top-level project folders. That's one person's Windows PC. Yours is probably worse if you have cloud CLIs installed. This is why "I never imported litellm" isn't a defense. It only had to be installed next to anything that starts Python.

The worst take of the day

A few hours in, @KyeGomezB posted "LiteLLM got compromised AGAIN. Maybe it's time to rethink your stack and switch to RouteHub, built by @swarms_corp."

Screenshot of a post by Kye Gomez, @KyeGomezB, Oct 21 2026 12:22 PM ET, quoting Socket's LiteLLM alert: LiteLLM got compromised AGAIN. Maybe it's time to rethink your stack and switch to RouteHub, built by @swarms_corp. 190x faster imports, minimal overhead, 20+ providers. 1,666 views.
@KyeGomezB on X, Oct 21 2026, captured 7:34 PM ET Oct 21 2026, real and unedited.

Funny thing, Kye. In our scan, your own swarms package requires litellm==1.76.1. That exact pin is the only reason swarms users were safe today. You had the best security story of the day and used it to sell a router. The lesson isn't "switch libraries." Any library you install can be the next one. The lesson is pin exactly, update on purpose, and keep secrets out of places Python can read on startup.

The numbers so far

  • Bad window on PyPI: 1 h 43 min (7:39 to 9:23 AM ET). Docker: about 2 h 33 min (7:46 to 10:20 AM ET).
  • LiteLLM downloads: 3,650,152 the day before (pypistats.org), 92.2M in the last month.
  • AI packages checked: 76. Depend on LiteLLM: 30. Accepted 1.107.0: 20 (8 plain, 12 via an extra). Blocked: 10, exact pins: 3.
  • Claude Code transcripts scanned: 1,193 (3.1 GB). GitHub tokens found: 0.
  • Stealer targets present on our dev box: 10 of 23, plus 9 .env files.
  • LiteLLM backdoors on PyPI in 2026: 2 (March 24, October 21).

My bet, and your turn

Prediction: by March 31 2027, another AI package in PyPI's top 1,000 ships a credential stealer through its own official release channel, and the stolen keys get used for inference before anyone posts about it. AI keys are the new crypto wallets. If I'm wrong, I'll write the correction with your name in the headline.

Your turn: exact pins plus a bot that bumps them, or version ranges plus a lockfile? Pick one and tell me why in the replies. @LiteLLM, you're welcome to answer too.

Rotate every key it touched, in order, tonight

The hard part of a night like this isn't revoking one key. It's remembering every key you have, where each one lives, and who else has a copy. The API Key and Secret Rotation Tracker ($5, Google Sheets and Excel) gets you there: every API key, token and password in one sheet, with where it lives, who has it, when it was last rotated, and a rotate-first list with what to update next. Names and locations only, never the secret values. A password manager stores secrets. This tells you which ones are overdue. $5 once, no account, no subscription.

Guaranteed: if it doesn't track your secrets and flag the overdue ones, email support@tensorust.com and we fix it until it does. A real person replies within one business day.

Related on tensorust.com: LLM proxy benchmark: 200 duplicate calls became 1, Theo's 60% stat is an outage chart, and DeepSeek gave away its engine. The $38-an-hour parts stayed home.

Method and data: package scan run 7:45 to 7:55 PM ET Oct 21 2026 against PyPI's JSON API; for each of 76 packages, the newest non-pre-release uploaded before 11:39:51 UTC, its requires_dist read with Python's packaging library, and a range counted as accepting if it contains 1.107.0 (dev and test extras excluded). Monthly downloads from pypistats.org. Transcript scan 7:33 to 7:40 PM ET over ~/.claude/projects, regex counts only. Dev box check: file existence only. X screenshots captured 7:34 PM ET, real and unedited. Incident facts from LiteLLM's incident post and GitHub issue #47826 (updates through 21:22 UTC), SafeDep, Railway's notice and status page (22:45 UTC update), NetSPI and Snyk for March.

First published here on tensorust.com on Oct 21, 2026. Also on X (@MattBusel) and dev.to. Related: LLM proxy benchmark, Claude Code vs Codex outages, DeepSeek DeepInfer, measured.

Get the next one by email.

What my AI agents tried this week, with the real numbers: what worked, what flopped, what made money. One email when there is something worth reading.

No spam, never sold. Every email has a one-click unsubscribe.

Read next

Free tool: LLM API cost calculator → Tokens in, tokens out, requests a day: monthly cost on 24 GPT, Claude and Gemini models.

All articles →

Get the receipts by email.

What my AI agents tried this week, with the real numbers: what worked, what flopped, what made money. One email when there is something worth reading.

No spam, never sold. Every email has a one-click unsubscribe.

1M+ X impressions in 4 days, run by AI agents · 8 iPhone apps live on the App Store · 69 Rust crates on crates.io · 520 GitHub stars · O'BLOCK out now, free on Steam

Built by Matthew Busel · code on github.com/Mattbusel · numbers as of Oct 18, 2026, click any to check

Popular in the shop

All 124 tools →

Browse: Bundles and kitsHome, family and schoolMoney and businessAI toolsSports and fitnessMaking and hobbiesFood and drinkIndie dev and launchTrading and quant

Free: Landing page teardown iPhone app cost calculator LLM API cost calculator Paid online: $49 Launch Check App builds Articles FAQ