Compromised LiteLLM 1.107.0 on PyPI Installs a Credential Stealer and Backdoor
safedep.io
safedep.io
At one point permission pop-up fatigue sets in we start giving any permission as if it's normal. We also become desensitised to isntalling tools: brew, npm, it becomes second nature.
"Oh, those 367 tools installed by package X? Yeah yeah, must be normal, that's how all these work now".
"Brew shows 59 packages outdated?". "Must upgrade". "Yeah, done. Perfect".
And the advent of agents and harnesses. It's not a matter of whether, it's when! OSes need to do something about it. Help users have complete separate "program space" at ease with better, easier, and lighter VMs if nothing else. I know, I know - Unix and Linux solved all this even before Alexander III of Macedon started wearing his nappies. Of course.
Sandbox comes in for the unknown ones and yes, its a pain to get the profile right.
From some of them perhaps, but plenty hide for -years- undetected.
I mean okay, it probably helps in some random cases, but the disease will not care at all. Easy to route around and we just wasted a lot of developer energy treating symptoms and ignoring the actual problems.
People are running around acting like cooldowns fix supply chain attacks. This is completely absurd. Imagine an antivirus that just makes you wait one day to install any new software or updates. Should we do that too? We should question what problem are we actually solving before this type of thinking gets even more out of hand.
What we need is actually reviewing all heavily used OSS code with as many eyes and agents as possible in a coordinated and decentralized way, and then federated reproducible signed releases. If we are going to have a one day cooldown, we must do something actually useful with it or people will see it does no good and stop doing it. Without a review plan, a day might as well be a year.
Like literally fund this with taxes or something like caring for public roads. Add it to our internet bill like a utility safety fee.
It would be like having a one-day quarantine against 500k viruses, which have a median asymptomatic time of 3 hours and stdev of 1 hour: sure, statistically some get by you. But it’s dramatically better than insisting on no protection except perfect protection.
Which ones? Not even xz-utils was years (it was weeks), and it’s the poster child for a attacker doing everything right until the very end.
(This is also different from what the GP argues.)
Not every malicious actor is a financially driven crypto-miner or credential stealer. It seems likely that some exploits are going to be sat on or used in a highly targeted manner such that we may never know they exist.
But again: it’s impossible to argue against a “silent majority” claim. The argument passes the sniff test for drug smuggling because we have separate evidence that most drugs are not interdicted. We have no such separate evidence for open source supply chain compromises.
I am aware of at least one evil firm that finds bugs like these months and sometimes years before they are public and sells the knowledge to spooks until someone else independently spots them and tells the public.
Only a matter of time before these types of firms introduce the bugs themselves given the incentives, if they are not already.
I mean, didn't Linux shells invent pop-up fatigue? I thought we (yes, we) all used to -y flag preemptively so the upgrades and installations/setups go through. Linux really did do it first, the agents are just more needy and their popups more verbose now, but not exactly new.
VM isn't a silver bullet.
Either way it's got nothing to do with security - I was never going to catch a vulnerability in the central debian repos by reading a list of dependent packages.
Discord does this with Firefox: It doesn't even tell you that a captcha failed or anything, just poof logged out and you must re reverify the same email you verified 10 minutes ago.
We have been a petri dish for insane megalomaniacs for too long, and now freedom is coming back to bite us, because it gave freedom to the worst imaginable people to oppress the rest of us.
You're getting downvoted probably because it isn't a serious suggestion. IRC is missing features and you don't have a meaningful reason to make it illegal.
For the record, I use IRC.
Water, food, housing, healthcare, telecommunications, computing (including artificial intelligence). I guess it's "socialist" to believe that these baseline needs should be, and can be, free for all of humanity.
One day we'll look back and laugh at the stupidity of our current state of civilization, that we'd need to pay anybody anything to live on this planet that provides all those things and more for free. Pity us, future people, I hope we grow up soon.
> planet that provides all those things and more for free
This planet does not provide healthcare, telecommunications, or computing for free (unless you consider nature's "the sick get eaten" approach "healthcare"). Housing is only free if you either don't value the labor or you are fine living in caves. Water and food could be free if you're only interested in drinking from rivers and foraging for fruit, otherwise we're back to whether or not you value the labor in farming or building the infrastructure for water collection and transport.
(for the record, I think those things should be all funded by taxes. I just think it is silly to claim the planet provides those things for free. We created those things, through millennia of toil.)
my boyfriend didn't have 2fa enabled, but google would still ask him to verify a code on his phone. recently his password leaked, the hackers got into the account and google never bothered them with an extra verification. amazing. the fact that they signed in from a completely different country? who cares!
(yes i enabled 2fa for him now)
No, you can block this with sandboxing tools. For my LLM agents, I use a tool called Nono, whose macOS implementation is built on the same foundation as sandbox-exec. One of the key features it supports (and it's not the only tool that does this) is proxying and the injection of credentials via the proxy. For example, when I run Codex at work, Codex does not have access to my Azure AI Foundry API credentials. It sends out requests via dummy credentials, and the proxy injects the real ones outside the sandbox.
The other thing that proxy does is let you restrict network access in various ways. So you can run something like LiteLLM so that it doesn't have access to the internet at large; it can only talk to Azure AI Foundry or AWS Bedrock or whoever your inference provider is. You sandbox LiteLLM separately from your agents, and you give it access to much less. The software firewall stuff isn't perfect but it is a significant defense against things like this.
There are also lots of other restrictions that are easy to do which mitigate this. Nono blocks access to the root of $HOME, then selectively allows access to paths within it, and also explicitly blocks access to common paths to secrets. So it's pretty easy to make sure that access to important things are blocked: SSH credentials, GnuPG socket (and local Unix sockets in general), local OS keyrings, etc.
The way I use tools like this is exclusively by writing policy, testing it, and revising where the policy is inadequate. I never get approval fatigue because I don't do approvals.
You're right that attacks like this are hard to defend against, and that we're used to tool sprawl, and also that LLMs can do things like install tools we don't expect them to themselves! But there are ways to anticipate and mitigate attacks like this. Sandboxing tools (including contained and VMs) that support credential injection are genuinely useful for this.
LiteLLM is frequently used in roughly the same scenario - trading virtual LAN-only keys for real ones as it relays requests to the inference providers.
LiteLLM isn't a sandboxing tool so it just can't perform as much risk reduction even when everything is working as intended.
And what nono adds over sandbox-exec is a uniform interface across platforms and some policy management tools. You can impose the same restrictions via the OS built-in mechanisms yourself via Seatbelt or a built-in interface like sandbox-exec. You can also combine an OS-level sandboxing tool like nono, zerobox, Anthropic's srt, Seatbelt, landrun, Bubblewrap, Fence, etc., with a VM-based one like Docker's sbx, smolvm, krunvm, microsandbox, or Shuru. So now you need two simultaneous supply chain attacks in unrelated projects to line up just right at the same time.
"Eventually you have to trust some part of your security stack" is neither particularly interesting nor evidence that there's no way to defend against supply chain attacks. Even if you only have one sandboxing tool and it's OS-level rather than VM-based, that becomes a single part of your stack that you can give special attention to in evaluating updates in a way that LiteLLM can't be.
There's also just the empirical fact that at this point, trusting LiteLLM's maintainers to lock down their release pipelines looks foolhardy. This is the second supply chain attack they've had in 7 months. It's absolutely wiser to choose a sandboxing tool you like, audit it to examine its release pipelines, code signing requirements, attestation strategy, and whatever else, then put LiteLLM inside that tool's sandbox than to just thow your hands up and say "I gotta trust something, so it might as well be LiteLLM!". Maybe nono ain't it either, idk. I'm still experimenting to figure out how I want my setup to work.
But I think neither the defeatism nor the relativism in this thread are very compelling.
Also put it in rust ….
It's not a guaranteed you'll know you've been hacked, but it's still quite a flag to leave. And there are services doing the equivalent of what you posted, but for cryptocurrencies: they contact you through email, SMS, snail mail even, if they detect that "coins at address ..." ever move.
There are ways to try to prevent this from happening in a first place. I wrote kow (keys-on-the-wire) to fix this. Apps only see placeholder tokens. The proxy injects real key from the vault into outbound requests for allowed hosts.
Author here. Apache-2.0. [1] https://keysonthewire.com [2] https://github.com/inflightsec/keys-on-the-wire
Okay, checked, it was March of this year: https://futuresearch.ai/blog/litellm-pypi-supply-chain-attac.... What even is time anymore in the llm age?
We work hard on improving the stability and security of LiteLLM on each release.
Please let me (krrish@berri.ai) know if you have any issues upgrading!
How did you address this issue?
Will upgrade ASAP. Thanks for the amazing product and best of luck with everything.
> No public commit in BerriAI/litellm contains data = "cook" or a cook/ folder.
> SafeDep assesses, with moderate to high confidence, that BerriAI’s private release pipeline built these wheels from an attacker-modified git source.
They revoked all but one developers, which is probably the right approach, but I'd pin LiteLLM to "something before this version" and keep it there until further notice!
Pinning is a good idea.
So far, we believe it came from the github oauth cli tokens which are embedded in claude code tool responses - https://docs.litellm.ai/blog/security-incident-oct-21-2026#g...
It's something we're still investigating. I'll update my thread on this post, as we learn more!
All I read was that it creates a directory from the build file but seemingly no description how new files or added dependencies slipped by. Was `cook.pth` a dependency that got automatically downloaded from PyPI on install and then the build system put it into dependencies?
--
Leaving this for others:
> BerriAI’s private release pipeline built these wheels from an attacker-modified git source. The attacker could have used a compromised maintainer or bot credential, a private branch or mirror, or the reference the pipeline builds from. A stolen PyPI token used from the attacker’s own machines fits the evidence less well.
Makes sense. It was that a maintainer or the private pipeline was attacked and the malicious dependency was injected there by squatting on the maintainer's local copy rather than the dependency being hijacked for everyone. Very clever.
What would catch it is someone rebuilding from the public tag and comparing the result, which almost nobody does for the python wheels. I have been treating attestations as the answer for my own project's releases, so this is a good reminder of where they stop.
This isn't the name of an entire package, but just a single file included in the package. .pth files are part of Python's import system. At startup, the standard library `site` runs automatically, and configures the (initial) places that Python will look for code to satisfy `import` statements. By design (because some people occasionally find it very useful), arbitrary Python code can be run from these[0]. The system searches the entire site-packages folder for these files.
The compromised build packages up a .pth file in such a way that installers will treat it as a "data file"; but because Python programmers are accustomed to looking for data files at paths relative to the current source file, installers put .pth files in places that will easily be picked up by the `site` scan.
So the point is simply that, once LiteLLM is installed, malware injected directly into the final package (not a dependency) runs at startup in the compromised environment even if you don't use the LiteLLM code explicitly.
Nothing "creates a directory from the build file". The attacker-modified source includes the entire "cook" payload directory and also modifies the build file so that the build system would include its contents. No dependencies are involved (unless you're thinking of LiteLLM as being a dependency for something else).
The Python ecosystem has been working on mitigations for this. Starting in 3.15 the .pth file system is being reworked[1], but a deprecation period is necessary. Also, the PyPI repository has an opt-in system called "Trusted Publishing"[2] which is supposed to allow verifying that a wheel was built from the appropriate source directly using GitHub's CI mechanism. (Opt-in because of the long tail of developers who don't use this or any other CI system and shouldn't be expected to learn them for a small hobby project.) However, since the attacker did use the CI system from a separate GitHub repository, and compromised multiple maintainer accounts, I imagine it was possible to defeat that protection as well.
If you don't need the `site` mechanism for your project (of course, this needs to be tested per project), it can be disabled by passing the -S flag to Python[3]. This has always been available, but awareness seems to be low.
Historically, Python packaging has overall had a pretty lax security posture, and new attempts to improve that are often delayed by the consensus process and by backward compatibility concerns.
[0]: It's possible to put arbitrary code directly in the file, but rather unwieldy. Interestingly, this payload is neatly organized: the .pth file simply runs an import statement and appears to keep hundreds of lines of code in two actual Python files: one that works directly, and one that sets up a sub-hook called `sitecustomize` (another explicit provision of the `site` configuration system).
[1]: https://docs.python.org/3/whatsnew/3.15.html#whatsnew315-sta...
[2]: https://docs.pypi.org/trusted-publishers/
[3]: https://docs.python.org/3/using/cmdline.html#cmdoption-S
Here's what we know so far: https://docs.litellm.ai/blog/security-incident-oct-21-2026#h...
- Krrish
This was captured in the request/response logs.
The attacker, having gotten access to the logs, then looked for this and used it.
So - yes a local github cli oauth token, but not the machine.
That's pretty hand wavy. What did y'all have CC doing that it had your GitHub CLI OAuth token in its context at all?
Stuff like this is why my coding agent is a coding agent not shell agent that basically own the machine. Mine has no tool for shell use narrow tools specific things like ripgrep, finding files, and deleting files that limit the paths to explicit workspace directory.
I take care of commits, push/pull, building wheels, and publishing wheels myself. It really doesn't take the much time and the coding agent frees up a lot of my time.
I too was surprised when I see my colleagues telling me that these actions are "not maximizing your efficiency".
They'd rather hand all controls to the LLM, and then be surprised when shit hits the fan.
Ripgrep has the `--pre` flag and `--hostname-bin` flag that enables it to execute arbitrary commands.
> finding files, [...]
Does that tool invoke the `find` command? Because `find` has the `-exec` flag which could then be used to invoke arbitrary commands.
I really think the only safe option is putting your agent in a virtual machine with only a copy of your code (sans credentials), let the agent work, and then copy it back and manually audit it.
The best improvement would be to blame yourselves instead of Claude.
That's fair feedback. What I'm trying to express is the complexity of it.
For this to work:
1. The attacker had to get access to our internal gateway
2. Claude code had to embed the github oauth cli token in tool call responses (not directly, but as part of an embedded url call).
3. We had to enable request/response logging.
4. The attacker had to be aware of this token logging circumstance, then harvest multiple user account tokens (one of which had to belong to an org admin)
5. The attacker had to wait for / hope that we would expand the release trust boundary (as we did on Monday)
among other things. This wasn't a "whoops we had shitty governance around our auth tokens" kind of situation, it involved a number of non-trivial circumstances many of which were beyond the attacker's direct control, including Claude Code behavior of which we were not previously aware of, and a sophisticated attacker.
- Krrish
As for sophisticated attackers, I think that phrase should probably be retired at this point. Every attacker is a fairly sophisticated now since you can automate that sophistication. Attackers before used to have a set of tools that would try to connect or execute a bunch of automated prescripted checks, while any attacker now can automate the generation of those tools and scripts on demand
Risk is ensuring enough security researchers are finding these and quarantining these before that default cooldown lapses.
I’m unsure how to automate this properly, maybe an LLM is the best starting point.
There needs to be a service that does reproducible builds of opensource projects as they sit and publishes results for people to scrape freely.
To be robust itself against attacks, likely 3-4 services.
But then that needs funding to be sustainable … and companies are incredibly cheap. Especially right now. As such… shrug :(
Maybe something as a skill for LLMs to run that actually checks build reproduction from source for a project and all of its dependencies? But then that’s gonna burn some tokens ….
I do this for personal projects … but at work they’ve started rationing tokens… as such… idk?
Ultimately, you need someone to verify releases and that probably means paying for it. I know Sonatype paid solutions utilise their own internal research to allow/block new releases.
We did a small survey of major incidents after shai-hulud and came to 2d cooldowns through that
(This is a situation where everybody benefits from high quality data. If you have data that contradicts mine, please share it!)
[1]: https://blog.yossarian.net/2025/11/21/We-should-all-be-using...
"Installing the Aikido Safe Chain is easy with the installation script.
curl -fsSL https://github.com/AikidoSec/safe-chain/releases/download/1.... -o /tmp/install-safe-chain.sh \ && echo "9e4af7107f06d9c0d758cb08fb36804c2af88e24972f3a9d3f8c2bd0ca002adf /tmp/install-safe-chain.sh" | sha256sum -c - \ && sh /tmp/install-safe-chain.sh \ && rm /tmp/install-safe-chain.sh "
(facepalm)
1792590232 | Litellm 1.107.0 Compromised | https://github.com/BerriAI/litellm/issues/47826 | https://news.ycombinator.com/item?id=50180845 | 0 comments
I'm not saying everyong should migrate after there's a vuln, but I'm definitely saying that. Unless it's something huge and foundational like a programming language (PHP gets a second chance), just migrate within the next couple of weeks.
I didn't even have it installed the first time, so the ideal programmers, (read, your competition), actually suffered 0 vulns from this dep, if you suffered 1, that's already pretty bad, being burnt twice should be a wake up call. If you get hit 3 times by the same dependency, it's a lost case.
second? i haven't kept count, but we have to be somewhere in the hundreds of chances now
If it matters, I am mostly interested in the aspect of having a proxy that unifies multiple ollama and openai-compatible endpoints with model-based routing and failover. Optionally with api-keys, reporting, budgets, etc. I do not particularly care about the MCP gateway, Agent-To-Agent thingy, and whatever else LiteLLM bolted on over time
That said, I am looking into alternatives. Two times in one year is really a terrible look.
Now that AI makes it cheaper to build such tools in-house, the case for adopting a maximalist framework and trusting that entire supply chain is a lot weaker.
I don't think memory safety would have helped here.
> the case for adopting a maximalist framework and trusting that entire supply chain is a lot weaker
You mean the Rust ecosystem?
Taking the definition from another user on this comment-chain:
"an OpenAI compatible endpoint routing across multiple providers based on latency"
If the endpoint is truly OpenAI compatible, you can just switch out the vendor by switching out the HTTP address, we are talking potentially about a single line change.
- LLM_HOST = "api.openai.com" + LLM_HOST = "api.competitor.com"
It sounds silly, but remember that software is a winner-takes all game, 99% of devs will lose, so if you are seeing 99% of devs do the same thing, it isn't surprising that it's a grossly wrong choice. It takes skill and guts to be in the 1%, reject the mainstream trends, and just write code without grasping at external imports to do even the most basic things.
I'd like to take this opportunity to sell out, I'm open for contracts if you are looking for a remote 1% dev. Early stage startups only, email in userpage.
Turns out Ancient Aliens was onto something all along.
Their docs list LiteLLM's vulnerability from March... https://i.imgur.com/TPVrVyW.png
> OSS Users > For the time being, please pin your version to 1.106.2 or any explicit version published prior to now.
> Enterprise Customers > There currently exists a private LiteLLM registry for enterprise customers, in which we are distributing an embargoed release that remediates a vulnerability whose disclosure date is scheduled for October 27. Our private registry is not affected. If you are an enterprise customer pulling from our private registry you are not affected.
Seems a little unethical
1. there is a second vulnerability that will be disclosed next Tuesday (can't be this one because talking about it as undisclosed in the GH issue disclosing it makes no sense)
2. the patch for that vulnerability is somewhere in the diff between $current_public_release and $current_enterprise_release
3. You have to pay to get $current_enterprise_release
They might not be selling the vulnerability directly, but they are selling access to the patch that fixes it. Which would be enough of a hint even in pre-LLM times. And unlike other vendors they don't just claim "you get faster updates and additional features" or something like that, they directly point out that if you buy now you get advance access to the fix to an unannounced vuln
I'm not saying they are advertising this to bad actors. But if they wanted to do that with a shred of plausible deniability, this would be the way to do it
There exists a critical vulnerability which affects only Enterprise LiteLLM deployments, and does not affect OSS deployments.
We have provided our customers with patched releases distributed via a private registry and are allowing them some time to update their deployments before we release the fix in our public registry and disclose the vulnerability details. Releasing the fix publicly in an open source product would be a de-facto vulnerability disclosure.
1. Google Cloud Outage [0]
2. eMudhra CA private key Leak [1]
3. PingCap TiDB 10.6 TB data Leak [2]
4. PHP2Shell uncovers critical CVEs (with AI) [3]
...and now we have Round 2 of a LiteLLM compromise after the first one in [4].
[0] https://news.ycombinator.com/item?id=50163961
[1] https://news.ycombinator.com/item?id=50166579
[2] https://news.ycombinator.com/item?id=50173716
https://github.com/BerriAI/litellm/issues/47826
oh boy. Announcing that there's a private enterprise repo you should be paying for if you don't want a credential stealer in your build is quite the optic, and then announcing there's an undisclosed second vulnerability that's being distributed, just not to the poors...
Also if you don't like organizations fixing vulns without releasing the open source first, you're going to be upset when you learn how every major vuln and associated patches are distributed long before the fixes hit the repos. A timely example of this is PHP, literally today.
Sorry, there was a paid-for PHP release that fixed it I could have gotten a week ago, and that they publicly announced existed, and it was just people who don't pay for PHP who had to wait...?
You can argue about whether the "publicly announced existed" part since they don't advertise for any single package, but that's the ecosystem you buy into.
The way you've written this is substantially misleading. RedHat receives notice of the vulnerabilities so they can prepare packages to be available the moment the embargo lifts, which I guess technically could hit the public packages a tiny bit earlier, but they are not releasing fixes of embargoed vulnerabilities to their commercial clients before the embargo lifts.
This is substantially different from the policy I've quoted that I am objecting to.
There exists a critical vulnerability which affects only Enterprise LiteLLM deployments, and does not affect OSS deployments.
We have provided our customers with patched releases distributed via a private registry and are allowing them some time to update their deployments before we release the fix in our public registry and disclose the vulnerability details. Releasing the fix publicly in an open source product would be a de-facto vulnerability disclosure.
However, if anyone is looking for 20x faster and less "targeted" LiteLLM alternative - I'm work on one in Go. That's why GoModel it's called. https://github.com/ENTERPILOT/GoModel/
I myself have written a small llm proxy in Go, doing nothing but injecting the real API key to outgoing requests while itself validating virtual keys it generates, and it works great.
- being resilient to upstream provider downtime
- centrally managed config/controls
- visibility and allocation into usage and costs
We are deploying a gateway at work primarily for these three.
At home, GoModel's virtual models have been super helpful for testing out new open weights. I can change the model deployed in vLLM without having to change any of my downstream tools, which get a stable name.
/s
If someone just need an AI Proxy with no deps.
Agents and malware will eradicate all goodwill left.
Good by internet.
Tell em Tom Zubiri sent ya (I don't get a commission, just good karma)
I use it, I don't cooldown, proper version pinning for me.
LiteLLM has one of the nicest programmer UX to use but this is not good at all.
Just checked if litellm crept in with any packages I installed recently. Fortunately it didn't, but I'm working on an OSS AI agent harness so its certainly a concern and I'd like just flatout block litellm so I don't have to worry about picking it up as transitive dependency. Guess I'll have to vibe a script and remember to run it. Sigh.
uv pip install -r requirements.txt --exclude excludes.txt
excludes.txt is basically like an inverse requirements.txt. Your requirements.txt could have this... pandas
scikit-learn
matplotlib
...while excludes.txt has this... numpy
... and uv would resolve the dependencies in requirements.txt, excluding numpy from the dependency graph entirely and ignoring any dependencies that would have been introduced by numpy itself.EDIT: You can also configure this for uv directly in a pyproject.toml file:
[tool.uv]
exclude-dependencies = ["numpy"]https://www.gingerbill.org/article/2025/09/08/package-manage...
I appreciate the feedback. We work hard to make every release safe and secure. The attack was novel, and I'd love your feedback on how we can improve our ci/cd further.
https://docs.litellm.ai/blog/security-incident-oct-21-2026#h...
It's really not as bad as the accumulated headlines and exploitative hype make it sound.
It's similar to the mass hysteria and moral panics over things like child abduction. Media reports make certain dangers seem much more important than they really are, when considered in context.