1004: TanHacked

š **Source:** [1004: TanHacked](https://share.snipd.com/episode/85d595ef-8550-43bb-bb12-2507db4d9120)
## Highlights
- **Mini Shai Hulud Is Latest In Recurring Worm Series**
- Scott and Wes frame the incident as 'Mini Shai Hulud', part of a series of supply-chain worms dating back to 2025.
- They reference past waves hitting big services like PostHog, Zapier, and TanStack to show recurrence and escalation.
Transcript:
Scott Tolinski
Tan Stack got Tan hacked. Vercel got their walled garden penetrated. After stealing content for years, Udemy got their content stolen. Lovable, they got their vibes snatched. And now NPM and PyPy have been hit with a major supply chain attack targeting several popular JavaScript and Python packages. This is Shia LaBeouf. I mean, Shihalud, which is the latest worm in a series of Shihalud worms. The original Shihalud worm showed up back in September 2025, which feels like a century ago at this point. And where malicious versions of multiple popular packages were published to npm they contained the post install script that harvested sensitive data uh and sent it to github public Repos named shy halud so that's why we have the name shy halud here i also think that's a star star wars thing shy halud that's a sick hardcore band if you're into hardcore music look up Shy halud sick band it's it's actually from it's actually from the movie uh dune by the way in case you were wondering we're just gonna just gonna run through uh pissing off people here The new shy halud 2.0 dropped in nove 2025, and Post Hog got their hog posted, and Zapier got zapped, and Postman also got their hog posted with the new Shai Hulud. And then it struck again as Shai Hulud 3.0 in December of 2025, and now, I don't know why they don't call this one Shai Hulud 4.0, but this is mini Shai Hulud. Yes, this is mini Shai Hulud. Yes, right. It is mini. It's a little mini worm. Wes, Shai Hulud is a worm in Dune, just in case you want to get the reference, if you've never seen the Dune movie, which I assume you have. No, sounds dumb.
Wes Bos
This is insane. ([TimeĀ 0:00:00](https://share.snipd.com/snip/8ba415c7-9c02-42b5-8a50-bbfe680f76af))
- **Cache Poisoning Gave Attackers Publish Power**
- The Shai Hulud worm exploited GitHub Actions cache poisoning to gain elevated publish tokens.
- Attackers poisoned the PNPM store cache via pull_request_target so a later release workflow ran malicious code and exfiltrated an OIDC/NPM token.
Transcript:
Wes Bos
So what happened? The publishing sequence of TanStack, all of the TanStack packages, along with several other packages in the ecosystem, were compromised. And they were able to publish a new update of the package that then had like a post install script in it. And then that went in harvested credentials. But how it actually happened, this was not like some maintainer got his like password stolen or something was run on their computer and it lifted credentials. How actually happened was absolutely nuts. So what happened was GitHub actions have caches. And when you send in a pull request to a repo, that repo may have several GitHub actions that are in there. So in the case of TanStack, they had ones that would check the bundle size, make sure you're not accidentally sending in a pull request that's making the bundle size much bigger. And then there was other ones that would like check speed, you know, there's, there's often there's things that will simply just run every single time that someone sends in a pull request. And then there's other ones that are a little bit more elevated, which is like, you don't actually want to, like, for example, if someone were to pull request against a syntax website, We would have to approve that before it actually did a pull request deployment because they could be sending in code that would do malicious stuff. But what happened here is they took advantage of the fact that these GitHub actions have a shared cache. And I guess when you're making a GitHub action, there is a pull request. You can either have a pull request hook or a pull request target. And when you use pull request target, they then have a shared cache between other ones. And this took advantage of that by poisoning the PNPM store directory. So it built a brand new thing. Then it took its malicious code and injected it into the PNPM store in a place where when something legitimate was merged, that the sort of the elevated release.yml workflow would run. It would know to actually look up this thing and run it. So they poisoned the PNPM store cache, and then it turns out they just deleted all the code and then closed the repo. But that PNPM store cache was still poisoned. Then when a legitimate thing was merged, the release GitHub action was run, and it looked it up, it had the poison cache, and it ran this script that was in there. That then failed. However, in the cleanup code of it failing, it was able to capture what's an OIDC token, essentially just like a JSON web token for NPM. And then that was how they were able to then capture a legitimate NPM publish token that can then be used to publish anything. ([TimeĀ 0:02:14](https://share.snipd.com/snip/8e25976e-d630-4dfb-8c01-9d58c80845ba))
- **Worm Used Auto Run Hooks To Self Propagate**
- The worm self-propagated and targeted auto-run hooks to spread and persist across systems.
- It injected into postinstall, Claude settings JSON, and VS Code tasks.json so opening tools could auto-execute the payload.
Transcript:
Wes Bos
And the crazy thing about this is it was like, like it was a worm. So once one of them was compromised, it was able to self-propagate and publish through other packages. And then it sort of just like ate its way through the ecosystem and eventually got its way into like the Python package management system as well, which is absolutely nuts to see. Yeah. Yeah.
Scott Tolinski
And it's again, you know, we're talking about TanStack here. This has hit a lot of packages this morning. And this is just at the time of recording this a ton, not only just the TanStack, there's a ton of UiPath packages, which I had never heard of UiPath before. But they have a lot of packages, and they got hit. Other popular packages are some, shoot, what was the one that I was, oh, Mistrial. Mistral. Mistral. Mistral. I always call it Mistrial. I don't know why. Mistral. Mistral got hit. CMUX Agent MCP. There's just a number of different packages that got hit. So this is not just are you using TanStack or not? And I would imagine by the time all is said and done here, there will be even more.
Wes Bos
One interesting thing about the worm is that it tried to inject itself into other places that would auto run. So like at the end of the day, once this thing was published to the thing, like once the end user would then install it, it would have like a post install script that it would install from Like a different location. And then it would run some stuff and try to harvest credentials. So it was looking, sorry, I'm really blown out on my camera here. It would try to harvest like different credentials from AWS and what it just looking for stuff on your computer. I'm sure that there was some end game here, probably half for we need more compute to run our hacks on and then half for we're actually looking for compromised information. But one thing it did do is it stuck stuff into other places that will automatically run code. So it stuck it into the clod settings JSON and the VS Code tasks.json, which when you fire up clod or fire up VS Code, this will automatically execute. Yeah. I mean, this is how worms operate, right? They move from place to place. They dig themselves in. Worms are not this fast. I mean, there's a reason why. ([TimeĀ 0:06:10](https://share.snipd.com/snip/b9b8fd76-cee0-4071-a409-bb1174ee71cb))
- **Dead Man Switch Threatened Complete Data Loss**
- The malware included a ruthless dead-man switch to deter token revocation.
- It polled GitHub and would run rm -rf on the home directory if it detected a revoked GitHub token.
Transcript:
Wes Bos
But another crazy thing is that the hackers installed a deadman switch. So if you did end up installing this thing on your computer, it would constantly ping out to the GitHub API to see if your GitHub token had been rotated or if you had revoked your GitHub Token. And if you had revoked your GitHub token, it would run rmrf on your home directory. Oh, shit.
Scott Tolinski
Yeah. Oh, yeah. That stuff is freaky because I feel like there's just so many people who would not even know that this was on their machine maybe it's on their machine they'd run it and then goodbye uh To you to your life there man that that is uh yeah it's a scary thing to to think about. And that dead man switches, it's ruthless, is what it is. Have backups, ([TimeĀ 0:08:35](https://share.snipd.com/snip/342dd17b-10cb-4600-a87d-555e6c79f404))
- **Avoid pull request target In GitHub Actions**
- Maintainers should avoid using pull_request_target in GitHub Actions and scan workflows for risky configurations.
- Use security tools like the Century security review skills and the SNYK Labs GitHub Actions scanner to detect dangerous action setups.
Transcript:
Wes Bos
I think partially on the maintainer side, obviously don't use that pull request target in your GitHub action, right? I feel for all the folks that work on Tansac because they have done so much to make sure that they were secure, but it wasn't even that somebody's computer was hacked. It was simply just this poisoning of a shared cache, which is nuts to think about. But like on like a user point of view, you know, like how do you we're.
Scott Tolinski
Well, let's stick on the maintainer for just a second. Yeah. So obviously don't use that. There is a set of security review skills from the Century team that are really worth checking out. I also use those in my S stack skill tree. So if you're using AI, the security reviewer skill can definitely help if you are using AI for stuff. There's also a GitHub actions scanner made by SNYK labs, who does a lot of SNK labs. It. Yeah, he's got to know how to pronounce anything today. I just say S-N I just, that's not a word to me. That's a fake word. From SNCC Labs, this will scan your GitHub Actions for security issues, which they do great work over there. ([TimeĀ 0:09:38](https://share.snipd.com/snip/4f90f87e-cb64-49c6-956a-4073a307b600))
- **Use Package Scanners Like Socket To Get Early Alerts**
- Use third-party scanners that monitor package publications to catch malicious releases fast.
- Socket.dev scans every NPM publish and reportedly detected this worm within six minutes, providing early warning before npm removal.
Transcript:
Wes Bos
And you have to wonder, like, why is NPM not doing this? You know, I think something's got to change in this. This was not really an NPM issue, but also, like, this is such a big ecosystem. Absolutely everything uses NPM these days. And it's such a huge target that they're obviously going to be targeted by these hackers. ([TimeĀ 0:11:42](https://share.snipd.com/snip/1926bc28-6ad3-4d96-8196-734b3cb6ccbf))
- **Registry Scale Makes Security Defaults Hard**
- Large registries face trade-offs between security defaults and breaking millions of users.
- NPM likely hesitates to enable strict defaults because changes can disrupt non-technical users and numerous ecosystems like Home Assistant.
Transcript:
Wes Bos
This was not really an NPM issue, but also, like, this is such a big ecosystem. Absolutely everything uses NPM these days. And it's such a huge target that they're obviously going to be targeted by these hackers. So I really think NPM needs to step up here and implement some bigger things because they have like two-factor authentication now, every time you want to publish something. And that seems to be like the only thing they've done in the last little while i'm sure they've done more but like they really need to be doing something like step security or sockets doing
Scott Tolinski
Yeah from as a as a user though uh as a consumer of npm packages and let me tell you open up wide uh because you're getting gigabytes of npm packages on your machine uh What can we do to help Ourselves here? I think one of the things that people have been kind of going around and talking about is the minimum release age settings. I use PNPM instead of NPM as my package manager, and PNPM has this on by default. So if you are a PNPM user by default in the latest version, only packages that are 24 hours old can be installed. So that's one thing. PNPM actually also has a, it blocks scripts from running by default. There's like a very annoying thing that pops up and you have to approve the scripts. Well, this is why you have to approve the scripts from running. It's there to save you. So PNPM can feel obnoxious at first, but again, that is saving your ass. And also PNPM isn't the only package manager with this minimum release age setting. All of them have it, but they don't have it on by default. So Yarn has it with NPM minimal age gate, minimum release age in bun, and min-release in NPMRC, which can we just? These are like we got a hyphenated case here. We got camel case. We got all four different... Can we just agree on a property name for this setting? Like, who decided that NPM MinimalAgeGate was a good property name for that setting? That's ridiculous.
Wes Bos
PNPM...
Scott Tolinski
Let's just all standardize on the minimum release age.
Wes Bos
PNPM also has another setting, which is turned on in version 11, which is relatively new. So if you're using an older version of PNPM which I think a lot of people probably are it's called block exotic sub-depths which sounds kind of nice but essentially with your package.json You obviously can link to NPM packages and you say okay I, I want version, I want Lodash version eight, right? But that's not the only way to say where these packages come from. You can also link to specific Git commits. You can link to simply just external tarballs. And that's what was happening here, where when you installed it, it was was linking to a dependency that lived on github so this this even if this like that this malicious code was not Actually published to npm it was just linking off to like a like a git repo somewhere and then the when you npm install then it just goes and downloads that code from the actual resource So this block exotic sub depths when it's turned on will not allow you to to have those things that are not inside your package json inside of your root package json so like that's often The thing is i like eight levels deep of your package json there's some tiny little dependency that half the world is dependent on. That thing gets compromised. And then all the way up the package chain, everything is compromised. So that's another little step. And I think that's PNPM is doing a great thing for the community here by just turning these things on by default. Yeah.
Scott Tolinski
It kind of feels like they're the only ones who care enough to turn those things on by default. Yeah.
Wes Bos
I don't know. I think also like NPM has so many users that I'm sure they say, well, if we turn this on, it's going to break so many things. Like I'm sure they, they have like a hundred times the traffic and a hundred times the users. And like PNPM is used mostly by highly technical users. But you have to think like NPM is used in like Home Assistant and in everyone's vibe coded apps. ([TimeĀ 0:11:52](https://share.snipd.com/snip/439a126e-17f3-4e68-9d1a-69f18a2406b0))
- **Enable PNPM Minimum Release Age And Script Blocking**
- Use PNPM's safety defaults to reduce exposure to malicious publishes.
- PNPM enables minimum release age (24h) and blocks scripts by default so you must approve postinstall scripts before they run.
Transcript:
Scott Tolinski
I think one of the things that people have been kind of going around and talking about is the minimum release age settings. I use PNPM instead of NPM as my package manager, and PNPM has this on by default. So if you are a PNPM user by default in the latest version, only packages that are 24 hours old can be installed. So that's one thing. PNPM actually also has a, it blocks scripts from running by default. There's like a very annoying thing that pops up and you have to approve the scripts. Well, this is why you have to approve the scripts from running. It's there to save you. So PNPM can feel obnoxious at first, but again, that is saving your ass. ([TimeĀ 0:12:47](https://share.snipd.com/snip/a336e260-36b8-483a-8a1f-115b4ebcc294))
- **Block Exotic Subdeps To Stop Off Registry Code**
- Turn on PNPM's block exotic subdeps to prevent dependencies that point to git commits or external tarballs.
- The attack used off-registry git/tarball dependencies so blocking exotic subdeps stops those transitive vectors.
Transcript:
Wes Bos
PNPM also has another setting, which is turned on in version 11, which is relatively new. So if you're using an older version of PNPM which I think a lot of people probably are it's called block exotic sub-depths which sounds kind of nice but essentially with your package.json You obviously can link to NPM packages and you say okay I, I want version, I want Lodash version eight, right? But that's not the only way to say where these packages come from. You can also link to specific Git commits. You can link to simply just external tarballs. And that's what was happening here, where when you installed it, it was was linking to a dependency that lived on github so this this even if this like that this malicious code was not Actually published to npm it was just linking off to like a like a git repo somewhere and then the when you npm install then it just goes and downloads that code from the actual resource So this block exotic sub depths when it's turned on will not allow you to to have those things that are not inside your package json inside of your root package json so like that's often The thing is i like eight levels deep of your package json there's some tiny little dependency that half the world is dependent on. ([TimeĀ 0:14:20](https://share.snipd.com/snip/cc9421c7-679d-4a84-a881-5c7342041661))
- **Run Installs Inside Dev Containers**
- Use dev containers to sandbox installs and limit damage to your host system.
- Running installs and tools inside dev containers reduces the risk of a package having permission to delete your home directory.
Transcript:
Scott Tolinski
Yeah, yeah. Another thing you can do here, folks, is if you want, you can start using dev containers. CJ made a really great video called You Should Be Using Dev Containers, explaining how to get set up with dev containers. That could help with the sandbox nature of this all, right? This script had access to remove your home directory, if it's inside of a container, you're a bit safer there. So dev containers are certainly something that can at least protect your home system. ([TimeĀ 0:18:40](https://share.snipd.com/snip/94f2a547-f8c6-4b5b-a760-cd5682b993e1))