The Miasma / Shai-Hulud payload is still sitting in a lot of repositories right now. Here is how to tell if you are one of them, how to clean up safely, and what to do if you are locked out.
I got out. My account is back, my repositories are clean, my npm packages were never touched, and after four hard days my case was finally worked. I wrote that whole story in two earlier posts: part 1 and part 2. This one is not about me.
This week, with my access restored, I checked a publicly published list of repositories hit by the same worm that hit me. A clear majority are still infected. Days after the list went public, the live, credential-stealing payload is still sitting in repository after repository, untouched.
That means real people are still carrying this thing in their repos right now, and a lot of them almost certainly have no idea.
My honest first reaction, when that landed, was a quiet "oh, shit." Not for me, I was already safe by then, but for them.
If that might be you, I want to say two things before anything technical.
First: it is not your fault. The way this worm gets in is nearly invisible from your side. In my case it was a credential of mine, harvested earlier through a compromised dependency and reused weeks later. There was nothing obvious to notice and nothing obvious that I did wrong. If your account was suspended, you did not break a rule. This was done to you, not by you.
Second: you do not have to figure it out by yourself. I will be honest, I cannot tell you what actually got my own case moving in the end. Maybe it was all my desperate yapping, maybe it was simply my turn in the queue finally coming up. A few people tried to help and I was grateful for it, but I would not want to oversell that. What I can give you, with certainty, is everything I learned along the way, so you are not starting from nothing.
I keep thinking about who is still carrying this. Someone on holiday, with no idea their repositories are compromised. Someone new to all this, who has never had to think about supply-chain malware and would not know where to start looking, on their repos or on their own machine. Someone whose account was already suspended, staring at a login they cannot get back, quietly wondering what they did to deserve it. If that is you: you did nothing wrong, and there is a way through. Here is everything I learned, laid out plainly.
How to tell if you were hit
Do not trust the commit author. On main branches the malicious commit is disguised as the github-actions bot. On side branches it is often forged under your own name and backdated, so it reads like old, routine work. The reliable tell is a single file: .github/setup.js, a large obfuscated script that should not be there. Check every branch, not just your default one.
The one rule before you touch anything
The payload runs when you open the repository in an AI-assisted editor (VS Code, Cursor, Claude, Gemini) or when you run npm install or npm test. So do not do any of those with a repo you suspect. Work from a clone with no files checked out, so nothing can execute.
Two things need cleaning: the repo, and your machine
If you already opened an infected repo in an AI editor, or ran its scripts, assume the credentials on that machine were harvested: GitHub tokens, npm tokens, cloud keys. Rotate them. Cleaning the repository but leaving those credentials live just leaves the door open for next time. The full step-by-step for both is at the end of this post.
If you are locked out
If your account was suspended, keep your support ticket open and add a short note to it every day or two to keep it active. It can take days to get a human, and the wait is not a judgment on you. While you wait, you cannot clean the repos, but you can at least rotate the credentials you still control (npm tokens, cloud keys, and the GitHub CLI authorization once you are back in).
A note for the people who depend on these packages
If you only ever installed the affected packages from npm, you are very likely fine. In my case, and in the pattern I have seen, the published npm packages were never altered. The attack lived in the GitHub source, not in the registry. Check your own versions, but do not panic.
And one human thing
Writing software in the open was supposed to be one of the good parts of this work. You build something, you share it in public, strangers find it useful, and that exchange is the whole point. It is hard to watch that turn into something where opening a folder in your editor can quietly hand your credentials to an attacker, where a person who did nothing wrong can lose a decade-old account overnight, where a beginner's first taste of open source is a security incident they have no idea how to survive.
I do not have a tidy answer. The simple act of writing code in public now carries this, and I cannot stop turning over the obvious question.
What kind of world are we building?
It deserves more than a paragraph, and I will come back to it properly soon.
For now I only wanted to reach the people still carrying this, before something worse reaches them first. And there is one small thing you can do that helps everyone, not just you: if you were hit, cleaning your own repository removes one more live copy of this payload from the internet, and telling one other developer to check theirs reaches someone I cannot. That is how this gets smaller. If you are stuck at any point, say so, in the comments here or anywhere you can find me, and I will help.
Here is the full cleanup, step by step.
The full cleanup, step by step
The one rule above all: never let an affected repo run. No opening it in an AI editor, no npm install, no npm test. Work from a clone with nothing checked out.
1. Clone with no checkout.
git clone --no-checkout https://github.com/<you>/<repo>.git fix
cd fix
git fetch origin '+refs/heads/*:refs/remotes/origin/*'
2. Detect by the payload file, on every branch.
git for-each-ref --format='%(refname:short)' refs/remotes/origin | while read b; do
git cat-file -e "$b:.github/setup.js" 2>/dev/null && echo "INFECTED: $b"
done
3. Back up the evidence once.
git clone --mirror https://github.com/<you>/<repo>.git evidence.git
tar czf evidence.tar.gz evidence.git
4. Remove the malicious commit from each infected branch. For this worm the bad commit is usually the branch tip, so reset the branch to its parent:
git log -1 origin/<branch> -- .github/setup.js # confirm it is the latest commit
git push --force-with-lease origin <MALICIOUS_SHA>^:refs/heads/<branch>
Reset, not git revert: a revert leaves the payload retrievable at the old commit. (If a branch has real commits on top of the malicious one, do not use this as-is; rebase just the bad commit out instead.)
5. Purge the copies you cannot see. Because of the fork network a commit can stay reachable by its SHA after it is off every branch. Open a support ticket, give them the malicious SHAs, and ask them to garbage-collect and purge them via the sensitive-data removal process.
6. Rotate credentials properly (the step people miss). The way in is a harvested token, not your password, so 2FA does not stop it.
- Revoke the OAuth app authorization, not just individual tokens. GitHub stacks many tokens under one authorization (the GitHub CLI, for example); revoking single tokens or reinstalling your machine does not close it. Settings, Applications, Authorized OAuth Apps, revoke anything you do not fully trust and re-authorize fresh.
- If the GitHub UI errors out while you are revoking (the unicorn page), do not assume it worked. Come back when the platform is stable and confirm the app or token is actually gone. A failed revoke looks identical to a successful one.
- Rotate npm tokens and any cloud credentials (AWS, GCP, Azure) that ever sat on an affected machine.
Stay safe. You did nothing wrong.
Top comments (0)