A sophisticated supply chain attack exploited GitHub Actions' PullRequestTarget trigger and shared cache mechanism to inject malicious code into the TanStack package ecosystem, which then spread to Mistral packages and the Python ecosystem by harvesting credentials and using stolen tokens to publish compromised packages; the attack demonstrates how CI/CD infrastructure vulnerabilities can be weaponized to compromise software supply chains without directly compromising any maintainer's machine.
Deep Dive
Prerequisite Knowledge
- No data available.
Where to go next
- No data available.
Deep Dive
TanStack & MANY more packages affected - a deep dive & analysisAdded:
We got another big, a- a really big supply chain attack going on right now, and it's still ongoing and it's spread from the NPM also to the Python e- ecosystem, so maybe right now don't install any NPM or Python packages.
And make sure your system is set up securely in general.
I got another video on that. I'll share a link below, this video too. But first, I wanna give you some details on what if- affected and to find out if you're affected.
It started with the TanStack packages, TanStack Query, TanStack Router, TanStack Start, and so on. Yesterday, May 11th, in a pretty short timeframe, a couple of malicious, uh, packages, or actually all TanStack packages were published with malicious versions, uh, and it was contained quickly, uh, within 20 minutes. In the end it was detected and contained quickly, but all these malicious packages have been published in that timeframe or in that short timeframe here.
And then it continued spreading and it still is spreading.
It spread to the Mistral packages, which, ha ha, only have four users, but still that was affected because this malware acts as a worm and steals data, steals credentials, also potentially yours if it is installed on your system.
I'll get back to how to find out if you're affected in just a second.
But it continued spreading to more NPM packages because that is the idea behind it, and then even into the Python ecosystem, right now. This- this is just a few, uh, hours old here, uh, two hours at the point of time where- where I'm recording this.
Now, how do you find out if you're affected?
If you installed any TanStack package yesterday evening, in my case here, in- in the German timezone, uh, you must consider yourself affected if you installed it, uh, around that time. Keep in mind that is UTC, so you have to translate that to your time zone. In that time, then you must consider yourself affected, but since it's spreading to the Mistral packages, to many more JavaScript packages, here, you also must, uh, consider yourself or your machine affected and compromised.
And I'll share links to these posts below so that you can dive deeper and see the full list of all these affected packages as they have been published.
But as mentioned, it's still ongoing, so maybe don't install anything, uh, right now. There also are indicators, uh, of compromise. You wanna look for certain file hashes, SHA hashes for the router in a JS file, I'll also link this post below, and if you have a way of monitoring request happened on your machine, you wanna look for outgoing traffic to this URL, which would be another clear indicator data has been exfiltrated from your system.
What does compromised mean in detail?
It means that this malware does in the end two main things. The first important thing it does is it harvests data. It looks for NPM tokens, GitHub tokens, AWS credentials, other secrets, so it scans your system for typical locations where you store credentials and secrets and it collects them and sends them off to, well, to this URL I showed you. So it steals these secrets, but it does not just do that. As I mentioned, it acts as a worm, so it also uses these GitHub tokens that were stolen, for example, it uses them and the NPM tokens to publish more compromised packages. If you're the maintainer of another you have a CICD workflow that ran in that timeframe and that depended on some TanStack packages, then in that CICD workflow, the malicious, the compromised TanStack packages have been pulled in, the malicious code may have executed in there, and then in that workflow, so not on your machine, but in that workflow it also could steal certain credentials to publish a malicious version, a compromised version of the package your CICD workflow was trying to build.
So that is how it spreads. As I mentioned, it acts as a worm.
It's using these stolen credentials and tokens to publish more, uh, compromised packages, and that is how it spread to Mistral and then also other JavaScript packages and then even into the Python ecosystem, and this is where we are right now, and it still is spreading for all I know.
Now, how can you protect against that?
I created a video about that on my other channel, Academind.
I'll also link it below. The- the- the short story is you wanna make sure that you run your code or that you do your development not directly on your root machine if possible, but instead in some, uh, virtual machine, in a dev container, something like this. You don't wanna store raw secrets on your I mean, for AWS, for example, you wanna use their single sign-on approach instead of storing IAM credentials on your machine, for example, and use similar techniques for other services you may be using. In addition, you also, uh, wanna consider using services like Inphysical.... uh, or Doppler for storing your secrets in the cloud and not on your hard drive, not in.env files. That is something you may wanna do talk about stuff like that in that video.
And you also wanna use package managers and configurations that allow you to configure stuff like the minimum release age, like BUN allows you to do.
In the bunfig.toml file, you can set a minimum release age even if you do run BUN install, you only install packages that are at least X seconds old, eh, X days old, in this case here, in this example. Now PMPM has a similar feature.
The latest versions of NPM have a similar feature.
Uh, again, I covered that in that other video and if you do use something like BUN or if you have the right configuration for NPM but BUN does it as a default, for example, then it also blocks the execution of, for example, post-install scripts, so lifecycle scripts of those packages you're installing, which gives you another security mechanism because that malware typically relies on such scripts being executed on your system. So, using a secure package manager and/or secure configuration for that package manager, running your code in a virtual machine not storing plain secrets on your system, that is what you wanna do.
In general, but now maybe even more, because those attacks, attacks like these here, will just become more serious into how that attack worked because it's really interesting, but of course, we're having more of these.
I create a video like this almost every month now or maybe even more frequently because, for one, I believe they, they are easier to pull off now in the age of AI. It's easier to analyze, um, the, the packages or the, the, uh, dependencies you wanna affect and analyze their source code or their CICD setup for potential attack vectors. That is what happened here for TanStack.
It's not as if a maintainer's machine was affected, but instead, it was the TanStack CICD workflow that has been attacked, a- and I'll get back to that. So it's easier to, to look for vulnerabilities with AI. It's easier to write code, malicious code included, of course, and at the same time, we got that explosion in software.
We got more software being written than ever before, so there are more targets out there, including many targets that maybe don't care too much about security.
So, that makes those attacks more interesting Now how did this all start? It's really interesting.
As I mentioned, not a novel approach, not one we never saw before, but still quite elaborate. The TanStack team published a postmortem, an article where they explain how the happened, and I'll link that below too, but of course, I'll give you the summary here because in the end, this attack here relied on three main steps, which I'll explain in detail.
Uh, a PullRequestTarget/pawnRequest pattern, that is, then GitHub Actions cache poisoning across the fork base/trust boundary and runtime memory extraction of an OIDC token. Okay, w- what does that all mean? Again, you can read the article for all the let me give you the summary. Let's start with the PullRequest/pawnRequest pattern.
What is that? In order to understand that, we have to understand that GitHub Actions is, of course, the CICD solution, the CICD product by GitHub.
And I do have a course on GitHub Actions too, by the way, if you wanna learn how to set up GitHub Actions, how to use that product for CICD tasks, how to publish your packages Now like all CICD workflow tools, GitHub Actions relies on events that trigger workflows because, of course, is all about doing something in an automated way.
For example, releasing your website, publishing, deploying your website in an automated way when you push to the main branch, for example.
So you have various events that can trigger a workflow and push is one event, for example. So that you can say, "Okay, if I push to the main branch, for example," you can filter for different "then I wanna execute certain tasks.
I wanna install my dependencies, I wanna build the project, server." That is what you could do.
Now one other trigger is PullRequestTarget.
This trigger activates if there has been a pull request opened for your repository and that, of course, means anybody can fork your repository, do something in there, push something in there, fork, and then open a pull request with your repository and that would trigger this workflow. Sounds dangerous?
Well, it kind of is and it is what started this attack.
There also is the PullRequest trigger.
So I talked about PullRequestTarget before, but we also have PullRequest, which works in the same way, but PullRequest then runs the CICD workflow in the context of the forked repository. So whatever malicious may be going on in there, it happens in the forked repository, not in the base repository. So this is not a problem.Pull request target, on the other hand, runs in the context of the base repository and that, of course, is potentially dangerous.
It's potentially dangerous because anybody can open a pull request and of course, what happened in this case here for the atta- attack, in that pull request, in that fork, the attacker included the malicious code, the- the worm code, the malware in the TanStack, uh, repository, in the fork of it. But it included it in there.
Then the attacker opened the pull request and that led to pull request target being executed.
And then as mentioned, that then spins up a GitHub Actions runner and it then runs in the context of the base repository. What does this mean?
This does not mean that the attacker gets access to the base or can merge, uh, the malicious code into the re- but it means that, for example, the cache that's being used in there will be shared with subsequent GitHub Actions executions that stem from the base repository, potentially from totally different hooks like the push trigger. The next thing that happened was the cache poisoning, but what does this mean? Well, the attacker added code to their fork that would make sure that when the GitHub Action ran for that pull request target trigger, it would run a command, the hash files command which is supported by GitHub Actions, to store something in the GitHub Actions Now, what is that cache about? The idea behind the GitHub Actions cache to speed up those GitHub Action workflows.
So, you can, for example, hash dependencies.
The idea being that if a dependency your package depends on hasn't changed, why would you go through the entire installation process again?
That just takes time and time is money because you're billed for the runtime of your GitHub Action workflow.
And of course, you don't want to have workflows So, in most workflows, of course, for example, you install the dependencies of the TanStack packages and then you do the build step and build your TanStack package.
Again, if those dependencies of TanStack haven't re-install them? That's the idea behind caching and The problem is since that pull request target GitHub Actions execution and other GitHub Action executions, like the ones for the push trigger, share the same context, they share the same cache, and that is where cache poisoning comes in because the attacker was able to cache a malicious version or to put that malicious code into a dependency of TanStack, so to say, and cache that. So, then the attacker just had to wait for a normal GitHub Actions workflow to run for the TanStack packages, so for some maintainer to push some code, and then that other GitHub Actions execution would reuse the same cache that was set up by the malicious execution before and would now pull in the prepared poisoned cache, which included the malicious code.
So, that is how the malicious code got from the- the normal GitHub Actions execution for a by a normal maintainer who has not been affected by any malicious code.
That is how the cache was used as a transport vehicle between these two GitHub Action executions in the end.
And then as a third step, once the malicious code made it into a regular execution of a TanStack, uh, CICD workflow because of that push event, it stole a short-lived NPM token, an OIDC, uh, token, in the end to publish a malicious version TanStack package. Now, what am I referring to here?
NPM has that feature which is called trusted publishing, makes publishing NPM packages more secure because there are roughly two ways of publishing a package to NPM, you could say.
One is that you create a token in your, with your NPM account and you use that to publish new versions of your package. The problem is if that token gets stolen, anybody can publish, uh, a new version of that package. To ramp up the security, there is this trusted publishing process where NPM says, "No, you can't publish packages from your machine.
You have to go through one of these trusted providers," GitHub Actions being them, and there is a trusted publishing Actions which you can set up. And then as part of that trusted publishing process, a short-lived publishing token will be retrieved or will be requested, and then that short-lived token will be used for signing that new package version that is being published. So, in theory, the idea is that the token is hard to steal because it's not on the machine by any maintainer, and in addition, it's short-lived. Even if it were stolen, it's not active for very long. The problem, of course, just is if the code that runs in the CICD workflow that is requested that trust the token, if that code has been affected, then that malicious code has access to this brand-new short-lived trusted publishing token, and that is what happened here.
So, that malicious code abused this token token to then publish a new...... version of the TanStack package. Now, interestingly enough, this attack actually failed a bit because it did get that trusted token and it did use it to then reach out to the NPM API to publish a new version of the TanStack package that included this warrant, that included the malicious code. But it actually ended up in a GitHub Actions workflow that failed to complete because there was something wrong in the code that was pushed to CICD. So if the attackers would have paid attention to run their attack at a point in time where a valid code would be pushed, then, of course, this workflow would have completed and they would not have had to rely on publishing a malicious package manually by reaching out to the NPM API. But instead, they could have injected the malicious code into this workflow as they did, let this workflow finish successfully, and then a compromised version of TanStack would have been published whilst looking very valid because it was a normal push by a maintainer and the workflow finished successfully.
The way this attack worked, because that workflow did not finish successfully, made it a bit easier to, to catch what was going on by an external contributor here in the end because you could see that a new version of the TanStack packages was published even though the GitHub Actions workflow failed, so no new version should have been published. So you could see a mismatch there easier to detect this attack, which is kind of, yeah, one part where, um, the TanStack maintainers and we all got lucky.
Nonetheless, a pretty elaborate attack, as you can probably tell, that worked totally without compromising anybody's machine.
And even though it was caught quickly, it did serious damage because, as I mentioned, it is still spreading. And that was a long, eh, episode about all that, I know, but I really wanna emphasize, you have to work on making your system secure.
Uh, as I shared before, as I share in this video.
You, you wanna make sure that you reduce the danger of being affected. This attack, again, was caught quickly and yet, it is still spreading, so it's not over yet, and it is possible that not all attacks will be caught that quickly in the future. As mentioned, they got a bit lucky here. It could have been harder to detect this So then maybe the damage would be even greater but it's already pretty large here and it's not over yet, and we'll see more such attacks, I'm sure, because I mentioned the, the attack surface is getting bigger and more interesting.
There are more people writing code, lots of people that don't know what they're doing, and AI helps with running such attacks.
So, yeah, this is what's going on right now.
If you don't have to, maybe don't install anything.
Double check your setup and you'll find all the links below dive deeper, if you wanna see the full list of affected
Related Videos
Agentforce NOW AMA: Build with React and Salesforce Multi-Framework
SalesforceDevs
490 views•2026-05-28
How agent o11y differs from traditional o11y — Phil Hetzel, Braintrust
aiDotEngineer
450 views•2026-05-28
WEB TECHNOLOGIES UNIT-2 | Degree 4th sem BCOM Computers web technologies unit-2 full explanation💯✅
LearnwithSahera
1K views•2026-05-29
More tests are always better? How to use AI to identify tests that bring little value
Alliance4Qualification
335 views•2026-05-29
Search Algorithms Explained in 60 Seconds! 🤖💨
samarthtuliofficial
218 views•2026-06-01
People of Game of Thrones using JavaScript DOM
AltCampus
296 views•2026-05-30
Introduction to Problem Solving Part - 1 | Lecture 1 | Intermediate DSA
ascensionix
107 views•2026-05-29
🚀 BCS613C Compiler Design | Module 1 to 5 Schema Evaluation 🔥 | VTU 6th Sem 💯 #VTU #bcs613c #exam
Pranavaa-y4y
104 views•2026-06-02











