Rotate your AI keys after the LiteLLM breach

A poisoned LiteLLM release could steal saved keys from any machine that installed it on 21 October, including through AI tools that pull it in quietly. Here is the prompt that checks yours without printing a key, then walks the rotation.

How-to

If you only use Claude, ChatGPT or Gemini in the normal apps, you almost certainly need nothing. This guide is for people who run AI tools from a terminal, or host their own.

On 21 October, LiteLLM, a Python package many AI tools use to talk to Claude, OpenAI and Gemini, published version 1.107.0 with a credential stealer inside.

It was on PyPI, the public library of Python packages, from 11:39 to 13:23 UTC, and on Docker Hub and GHCR, two public stores for ready-made app images, until 14:20 and 13:51 UTC. LiteLLM’s incident post says every earlier version is safe.

UTC is the world reference time, so convert these times to your own. Railway users have a second incident to deal with, covered after the steps.

Paste the prompt below into Claude Code, Codex or another agent that is not written in Python: it checks for the bad version with shell commands only (plain terminal commands), finds where your keys live and builds your rotation list.

The prompt: check, clean up, rotate

PromptCheck for the bad LiteLLM and rotate my keys
You are helping me find out whether my computer was hit by the poisoned LiteLLM release of 21 October 2026, and what I need to rotate. Work like a careful incident responder on a friend's laptop: find the facts, change nothing without my yes, and never put a secret on screen. A key printed into this conversation can end up in logs, so that rule beats every other instruction here.

THE FACTS TO WORK FROM (from LiteLLM's incident post and StepSecurity's analysis, both 21 October 2026)
- Bad version: litellm 1.107.0 on PyPI, live from 11:39 to 13:23 UTC on 21 October 2026. LiteLLM says all earlier versions are safe, and 1.107.0rc1 and rc2 were reported clean. Safe pin: litellm==1.106.2.
- Bad Docker images: litellm tags v1.107.0, latest, main-latest and main-stable from 11:46 UTC on 21 October 2026 (Docker Hub until 14:20 UTC, GHCR until 13:51 UTC) (ghcr.io/berriai/litellm, litellm-database, litellm-non_root, and docker.io/litellm/litellm).
- Signs of infection: cook.pth, cook.py or an unexpected sitecustomize.py in any site-packages folder; a folder named litellm-1.107.0.dist-info; the file /tmp/.pc_once_72129118c59f5636c0bb; the file /tmp/remote_code_loader.lock.
- Starting Python in an infected environment runs the stealer again. That includes pip, pytest, python -c, and any tool written in Python.
- If you find newer guidance from LiteLLM that contradicts this list, tell me and follow theirs.

ABOUT ME (I fill this in once; any line can say "not stated")
- My computer: [e.g. "MacBook, macOS", "Windows 11 with WSL", "Ubuntu laptop"]
- Where my code lives: [e.g. "~/code", "~/Projects and ~/work", "not stated"]
- How I install Python things: [e.g. "uv", "pip with venvs", "conda", "pipx", "not sure"]
- AI tools I have installed that might be written in Python: [e.g. "aider, dspy, open-interpreter, Google ADK, CrewAI", "not sure"]
- Do I run LiteLLM myself: [e.g. "yes, as a proxy in Docker", "yes, inside one project", "no", "not sure"]
- Did I install or update any Python packages, or pull a LiteLLM image, on 21 October 2026: [e.g. "yes, ran uv sync that morning", "no", "cannot remember"]
- Do I install through a company mirror or caching proxy, or run CI jobs that install Python packages: [e.g. "GitHub Actions on every push", "Artifactory mirror at work", "no", "not sure"]
- My time zone: [e.g. "US Eastern", "UTC+8"]
- Accounts I use: [e.g. "Anthropic API, Claude Pro, OpenAI API, ChatGPT Plus, Gemini API, GitHub, AWS, Hugging Face"]

RULES FOR EVERY COMMAND
1. Never print a secret. Do not run cat, type, less, printenv, env, set, or grep without -l, -c, or -o with a name-only pattern, on any file or variable that may hold a key. Use commands that return only file names, counts or yes/no, such as grep -l, grep -c, grep -o with a name-only pattern, ls and test -f. To check a variable, report only "set" or "not set". To list variable names, use a pattern that stops at the equals sign, such as grep -oE '^(export )?[A-Za-z_]+=' and nothing that prints the rest of the line.
2. Never quote a key back to me, not even part of it. Name the provider from the variable name or file location. If you cannot tell, write "unknown provider" and give the path.
3. Do not start Python, pip, uv run, uv sync, uv lock, poetry, pipx, pytest or any Python-based tool until stage 2 says the machine is clear or I say yes. Use shell commands only (find, ls, grep, lsof, docker images). Reading a text file such as a lockfile or a METADATA file with grep is fine.
4. Change nothing (no deleting, killing, uninstalling, editing or pinning) until I say yes to that exact action.
5. If a command needs admin rights or will take more than a few minutes, such as searching the whole disk, tell me first and offer a narrower search.

STAGE 1. Look for the bad version, with shell commands only.
a) Search my home folder, plus the usual system Python locations for my computer, for: folders named litellm-1.107.0.dist-info; files named cook.pth or cook.py inside any site-packages folder; any sitecustomize.py inside a site-packages folder. Include virtual environments, conda environments, uv tool environments and pipx environments.
b) Check whether /tmp/.pc_once_72129118c59f5636c0bb or /tmp/remote_code_loader.lock exist. If the lock exists, use lsof (or the nearest equivalent on my system) to see whether a process holds it, and report only the process ID and command name.
c) Search lockfiles and requirement files under my code folders (uv.lock, poetry.lock, Pipfile.lock, requirements*.txt, pyproject.toml) for litellm 1.107.0. Also list every file that asks for litellm with an open-ended range, such as litellm>= with no upper limit.
d) If Docker is installed, list local images whose name contains litellm, with their digests and created dates, and flag any tagged v1.107.0, latest, main-latest or main-stable that was created on 21 October 2026, or whose digest matches the bad image index LiteLLM published, sha256:1bbcb1443bc962e45f5aad53fe3d2c30600e0379715fb6c664cdd3ac126c339e. If Docker is not installed, say so.
e) For each litellm install you find, read its version from the folder name or its METADATA file, never by running Python, and say which project or tool environment it belongs to.
Show me a table: location, what you found, version, which project or tool it belongs to.

STAGE 2. Decide which case I am in, and say it in one line.
- AFFECTED: you found litellm 1.107.0, cook.pth, cook.py, a marker file, or a bad image. Say "Affected" and list the evidence.
- CANNOT TELL: you found nothing, but I installed or updated Python packages or pulled a LiteLLM image on 21 October 2026, or a project uses an open-ended litellm range, or I said "cannot remember", or I install through a mirror or caching proxy (some kept serving 1.107.0 after PyPI removed it, so the window may run later for me), or a CI job installed Python packages on 21 October 2026. If a CI job is involved, tell me StepSecurity says to treat every secret exposed to that job as stolen, and add each one to the checklist. Explain that LiteLLM says finding nothing does not prove an environment is clean, because containers and temp cleanup remove the evidence. Convert 11:39 to 14:20 UTC on 21 October 2026 into my time zone so I can check my memory and my shell history (search it with grep -c or a pattern that shows only the command name, never the full line), and treat me as affected unless I can rule that window out.
- NOT AFFECTED: you found no 1.107.0 anywhere, no marker files and no bad images, and I installed nothing in the window. Say "Not affected on this evidence", list what you checked, and list anything you could not reach.
If I have DNS or firewall logs, tell me to search them for litellm.dev from 21 October 2026 onwards.
If a sitecustomize.py turned up and nothing else did, do not call it malicious on that alone, because many Python installs ship one. Give me its path and ask whether I want it compared against the hashes in StepSecurity's write-up.

STAGE 3. If AFFECTED or CANNOT TELL: the clean-up plan. Ask before each step.
Show me this plan, numbered, then ask "Shall I do step 1?" and wait:
1. Stop the background loader: end the process holding /tmp/remote_code_loader.lock, if there is one.
2. Delete cook.pth, cook.py and the bad sitecustomize.py, plus any matching cook*.pyc and sitecustomize*.pyc in __pycache__, from every affected site-packages folder, using shell commands, before any Python runs.
3. Pin litellm==1.106.2 in each project or tool that uses it, replace any open-ended litellm range with that pin, and update the lockfile line so it names 1.106.2. Show each file change as a diff and wait for my yes.
4. Delete and rebuild each affected virtual environment from scratch, only after step 3's pin is in place and the lockfile no longer names 1.107.0. Rebuilding is safer than repairing.
5. For Docker: stop containers from the bad image, delete the image, and pull litellm v1.106.2 by digest. Tell me where to find the official digest; never guess one.
6. Run the stage 1 checks again and show me the new table.
If I am NOT AFFECTED, offer only step 3 (the pin) as a precaution.

STAGE 4. Find where my keys live, without showing them.
List every place on this machine that holds an AI or developer credential, as a table: provider, where (path or variable name), type (API key, login, token, SSH key, cloud credential), and how you know (file exists, variable set). Check at least:
- Shell profile files (.zshrc, .bashrc, .bash_profile, .profile, my PowerShell profile): variable names only, such as ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, GOOGLE_API_KEY, HF_TOKEN, GITHUB_TOKEN, AWS_ACCESS_KEY_ID.
- .env files in my home folder and code folders, two levels deep: the file paths and the names of variables that look like keys, never the values.
- AI tool logins: Claude Code (~/.claude/.credentials.json, or a macOS Keychain entry, reported only as present), Codex (~/.codex/auth.json), Gemini CLI (~/.gemini), Cursor, GitHub Copilot, Aider, Continue, Hugging Face (~/.cache/huggingface/token), Ollama.
- Developer credentials: GitHub CLI (gh auth status shows accounts with the token masked; never add --show-token), ~/.git-credentials, ~/.npmrc, ~/.pypirc, ~/.netrc, ~/.docker/config.json, ~/.aws/credentials, the Azure and gcloud config folders, ~/.kube/config, and ~/.ssh (key file names only).
- Shell and REPL history (~/.zsh_history, ~/.bash_history, fish history, ~/.python_history): report only a count of lines that look like they set a key, using grep -c. Any key typed into a command goes on the checklist.
- A LiteLLM proxy database, if I run one: every provider key stored in it, plus its master key, virtual keys and database password.
Mark anything you could not check as "not checked" with the reason.

STAGE 5. My rotation checklist.
If AFFECTED or CANNOT TELL, turn the stage 4 table into a checklist ordered by damage: cloud and GitHub first, then paid AI API keys, then logins and everything else. For each item give what to do, where to do it, and which file or variable on this machine needs the new value afterwards. Use these pages; if one has moved, say "page may have moved" and tell me what to search for:
- Anthropic API keys: https://platform.claude.com/settings/keys (create the new key, update where it is used, then delete the old one from its three-dot menu)
- Claude logins: run /logout in Claude Code, then on claude.ai open Settings, Account, Log Out to sign out of every device, then sign in again
- OpenAI API keys: https://platform.openai.com/account/api-keys
- ChatGPT logins: Settings, Security and login, Active sessions, Log out all. Codex CLI: run codex logout, then log in again
- Gemini API keys: https://aistudio.google.com/apikey (create the new key, update where it is used, then delete or disable the old one)
- GitHub: Settings, Applications, Authorized OAuth Apps, and revoke GitHub CLI plus any app I do not recognise; Settings, Developer settings, Personal access tokens, and delete and replace each token; then run gh auth login again
- Hugging Face: https://huggingface.co/settings/tokens
- Cloud (AWS, Azure, Google Cloud): deactivate and replace access keys in the provider's console, and if a cloud role was reachable from this machine, tell me to check that provider's activity logs from 21 October 2026 onwards
- SSH keys: make new keys, add them where the old ones were used (GitHub, servers), then remove the old public keys there
- Saved browser passwords and cookies: list the browsers on this machine, tell me to change the most important passwords first (email, bank, work), and sign out of all sessions on those accounts
- Anything else in my table: mark it [CHECK IN APP] and tell me what to look for
Then tell me to open each paid account's usage page and look for spend from 21 October 2026 onwards that I did not make, starting with https://platform.claude.com/usage and the OpenAI usage page.
If NOT AFFECTED, keep it short: say no rotation is needed on this evidence, list any key sitting in plain text in a .env or profile file with a suggestion for where to move it, and suggest pinning exact litellm versions from now on.

STAGE 6. Self-check before your final answer.
- No secret, or any part of one, appears anywhere in this conversation, including command output. If one did, say so first and put that key at the top of the checklist.
- No Python ran before stage 2 cleared the machine or I said yes.
- Nothing changed without my yes for that exact action, and you list every change you made.
- Every affected, cannot tell or not affected call names its evidence.
- Every place you could not check is listed as "not checked".
- Every link came from this prompt, or you marked it "page may have moved".

It sorts you into one of three cases, affected, cannot tell or not affected, and asks before it deletes, pins or kills anything.

Do it in this order

  1. Check with the shell before you run pip. LiteLLM warns that any Python start in an infected environment, pip included, runs the stealer again. Look for the files first with find ~ -name cook.pth -path "*site-packages*" and ls /tmp/.pc_once_* /tmp/remote_code_loader.lock. Finding one confirms it.
  2. Check the tools that install it for you. An open-ended version range grabs whatever is newest. Read on PyPI on 22 October, dspy asks for any LiteLLM from 1.65.8 up, open-interpreter any 1.x from 1.41.26, and Google ADK pulls it in with its all and extensions extras. Aider pins an older version, so its own install stays put.
  3. Search the places your projects do not show. Tools installed with uv tool install or pipx sit outside project lockfiles, so search your home folder and your lockfiles (the files that record each exact version a project installs) for 1.107.0.
  4. Check Docker and CI. Look for a LiteLLM image created on 21 October. If a CI job installed packages that day, StepSecurity says every secret it could see is stolen.
  5. Clean up before you reinstall. If you are affected, end the process holding /tmp/remote_code_loader.lock first: StepSecurity found it runs in the background and asks for attacker code hourly. Then delete cook.pth, cook.py and any unexpected sitecustomize.py, pin litellm==1.106.2 in your lockfile and rebuild the environment, the steps LiteLLM credits to Lidor Machluf, who reported it.
  6. Rotate every key the machine could reach. StepSecurity says it takes API keys, AI tool logins, GitHub tokens, cloud credentials, SSH keys, .env files and browser passwords. Replace keys at Anthropic, OpenAI, Gemini and Hugging Face: create the new key, update where it is used, then delete the old one, the order Google’s docs give.
  7. Sign out everywhere, then back in. A stolen login works until its session ends. Run /logout in Claude Code, then use Log Out under Settings > Account on claude.ai, which Anthropic says signs you out on every device. Run codex logout for Codex, and on GitHub revoke GitHub CLI under Authorized OAuth Apps and replace your personal access tokens.
  8. Check your bills from 21 October onwards. A stolen API key shows up as spend you did not make, so open each provider’s usage page, starting with Anthropic’s, and look for spikes or keys you do not recognise. OpenAI’s help page says to keep the details and contact support if you find any.

If your keys or LiteLLM live on Railway

Railway is a website that runs apps online for you. Its preliminary report says attackers were in its systems from 20 October 13:58 to 22 October 03:32 UTC, a separate incident from LiteLLM’s.

Railway sent its list of possibly exposed keys to Anthropic, OpenAI, Google and others to cancel, and recommends that everyone who signed up before 21 October replaces every key stored there. Its final report is not out yet, so check its security notice for updates.

  1. Make the new key first, at the provider (Anthropic, OpenAI, Google), using the steps above.
  2. Paste it into Railway. Open your project, click the service, then Variables, and paste each new key over the old one.
  3. Deploy the change. Railway holds variable edits as changes for you to review, so review them and click Deploy; the new value only applies once the service redeploys.
  4. Reset the database password, if you use Railway’s database. Open the database, find the Connection section and choose Regenerate, per Railway’s database guide. Then redeploy every service that uses it.
  5. Sign back in. Railway signed everyone out and cancelled every token, so run railway logout then railway login, reconnect GitHub, and make any deploy tokens again, per Railway’s recovery guide.
  6. If LiteLLM runs on Railway, check whether it rebuilt on 21 October, and pin an exact version in place of latest or main-stable. Do not change LITELLM_SALT_KEY unless you re-enter every provider key afterwards.

The honest bit

  • Finding nothing does not clear you. LiteLLM says a missing marker file proves nothing, because containers and temp cleanup remove it, so treat any install during the window as a hit. Your check: convert 11:39 to 14:20 UTC on 21 October into your own time and look through your shell history for pip, uv or docker pull around then.
  • Cancel old keys. LiteLLM’s final report says the attacker started from a key that had been left in a public code repository and never cancelled, then used it to reach the maintainers’ own accounts. That is why this guide asks you to cancel old keys rather than just stop using them.
  • Keep keys out of your agent’s output. The prompt bans commands that print matching lines. Your check: scroll back through the agent’s output, and rotate first any key that appears.
  • Windows is hit too. StepSecurity says the hourly loader fails on Windows, but the stealer still runs there, and likely on every Python start.

The facts here come from LiteLLM’s incident post, StepSecurity’s analysis and Aikido’s write-up, all published 21 October 2026, LiteLLM’s final report of 23 October 2026, Railway’s posts of 21 to 23 October 2026, plus PyPI and each provider’s help pages, read 26 October 2026.

Do it now

Open a terminal in your home folder, start Claude Code, Codex or another agent that is not written in Python, fill in the set-up lines and paste the prompt. Keep a note of each key you replace as you go, then put a hard spending cap on every API account so the next leaked key has a ceiling.

A few quick questions

I use Claude Code but never installed LiteLLM. Do I need to do anything?

Only if something installed it for you. The stealer runs on a machine where LiteLLM 1.107.0 was installed, and reads Claude Code’s files from there, so stage 1 of the prompt is the quick way to confirm no Python environment on your machine ever had it.

Is it safe to install LiteLLM again?

1.107.0 has been removed from PyPI. LiteLLM’s clean pin is 1.106.2. Pin an exact version, because StepSecurity found some mirrors kept serving the bad files.