A machine or CI job that holds one of your tokens is running the Mini Shai-Hulud worm and uploading what it steals. Run the one-line check below. If it finds anything, clean the machine before you revoke the token: the worm installs a token monitor that deletes your home directory when the stolen token stops working.
Summary
- What: one developer's GitHub account gained 663 public repositories between 12 October 14:43 and 20 October 17:41 UTC, about 80 a day. Each is a dead-drop upload of stolen data from the Mini Shai-Hulud worm.
- Who found the worm: not us. StepSecurity, Corgea, Socket, SafeDep and Aikido have documented this kit since May. We caught one of its live victims.
- How we caught it: the hourly GitHub check we deployed on 19 October flagged the account at 04:27 UTC the next morning. It kept uploading: 84 more repositories that day.
- What we did: reported the account to GitHub on 20 October. We are not naming it; its owner is a victim. As of 22:33 UTC on 20 October, no new upload had appeared since 17:41 UTC on 20 October.
What we saw
Between 12 October 14:43 and 20 October 17:41 UTC, one GitHub account gained 663 public repositories. Every one has the description Shai-Hulud: Here We Go Again and a name made of two words from a list of 30 Dune terms plus a number. Each holds a README and a single results/results-<timestamp>-0.json file; the one we listed held 11,221 bytes. The account has one other public repository, which predates all of this. We read only public metadata: names, creation times, sizes and descriptions. We did not open the uploads.
Data table
| Day (UTC) | Uploads that day | Uploads so far | Recorded by GH Archive |
|---|---|---|---|
| Mon 12 Oct | 6 | 6 | 0 |
| Tue 13 Oct | 102 | 108 | 12 |
| Wed 14 Oct | 109 | 217 | 8 |
| Thu 15 Oct | 76 | 293 | 0 |
| Fri 16 Oct | 83 | 376 | 0 |
| Sat 17 Oct | 17 | 393 | 0 |
| Sun 18 Oct | 72 | 465 | 0 |
| Mon 19 Oct | 101 | 566 | 5 |
| Tue 20 Oct | 97 | 663 | 11 |
The uploads follow a daily rhythm. Most land between 02:00 and 15:00 UTC, which is 10:00 to 23:00 in UTC+8. Overnight they slow to about one an hour without stopping. The quietest day was Saturday 17 October, with 17. A rhythm like this fits a machine that someone uses through the working day better than a job on a fixed schedule, but it is only a pattern; from outside we cannot see the machine.
Data table
| Row | Total | Busiest hour |
|---|---|---|
| Mon 12 | 6 | 14:00 |
| Tue 13 | 102 | 14:00 |
| Wed 14 | 109 | 08:00 |
| Thu 15 | 76 | 09:00 |
| Fri 16 | 83 | 09:00 |
| Sat 17 | 17 | 07:00 |
| Sun 18 | 72 | 10:00 |
| Mon 19 | 101 | 02:00 |
| Tue 20 | 97 | 08:00 |
How the worm uses your account
Besides its command-and-control server, the worm stages what it collects in new public repositories created with the stolen token, under the token owner's account. StepSecurity documented the Dune-word names and the reversed description niagA oG eW ereH :duluH-iahS in the May AntV wave, and Corgea documented the same marker. In June, StepSecurity described the results/results-{timestamp}.json upload. SafeDep's analysis of the October tensorlake build shows the forward description this account uses. It also shows a new C2 domain and a token monitor that deletes the home directory when the stolen token is revoked; SafeDep found that the monitor arms only for accounts with no organisations.
The October wave is active. The Hacker News reported that the first malicious tensorlake commit landed on 7 October, and that version 0.5.144 reached npm a day later. Nothing we can see ties this account to tensorlake. Our GH Archive data shows the forward description in use since early August.
LimitsWhat we can and cannot see
- We can see that a token for this account can create repositories, and that something used it 663 times in eight days. That means a machine or CI job holding the token runs the worm, again and again.
- We cannot see how it was infected. The public record shows the uploads, not the package, repository or editor hook that started them.
- We cannot see which build it runs. The forward description has been in use since August.
- We cannot see what was stolen. We did not open the uploads, and SafeDep reports that the worm encrypts them.
- We cannot tell whether it has been cleaned. No new upload has appeared since 17:41 UTC on 20 October, as of 22:33 UTC on 20 October. The machine may be clean, switched off, or no longer holding a working token.
- Its npm packages are untouched. The account publishes 3 npm packages. The last release of any of them was in 2018, and nothing has been republished.
How we caught it, and what we missed first
Our retrospective GH Archive hunt, covering 1 August to 13 October, had already matched 12 of this account's repositories. The first was recorded at 03:05 UTC on 13 October, about 12 hours after the first upload. It was one of the 13 accounts counted in our long-tail post. That was an analysis, not an alert, and we did not act on the list then.
On 19 October at 16:56 UTC the same check went into our hourly GH Archive pipeline. Its first record of an upload after that came at 01:45 UTC on 20 October. The check flagged the account at 04:27 UTC, 2 hours 42 minutes later, with the note "Treat the owning account's tokens as stolen; check packages it can publish." It raised one finding for each of the 9 hours that day in which GH Archive recorded an upload, the last at 16:26 UTC. These findings go to our analysts. They do not alert customers on their own.
The limit is the feed. GH Archive recorded only 36 of the 663 uploads, and none of the 248 made between 15 and 18 October. A check built on it sees a sample of what a victim account does, not all of it.
Data table
| Day (UTC) | Uploads | Recorded by GH Archive |
|---|---|---|
| Mon 12 Oct | 6 | 0 |
| Tue 13 Oct | 102 | 12 |
| Wed 14 Oct | 109 | 8 |
| Thu 15 Oct | 76 | 0 |
| Fri 16 Oct | 83 | 0 |
| Sat 17 Oct | 17 | 0 |
| Sun 18 Oct | 72 | 0 |
| Mon 19 Oct | 101 | 5 |
| Tue 20 Oct | 97 | 11 |
Check your own account in one command
With the GitHub CLI signed in as the account you want to check, this lists every repository whose description carries one of the worm's markers. No output means none was found.
gh repo list "$(gh api user --jq .login)" --limit 2000 --json name,description,createdAt --jq '.[] | select((.description // "") | test("Shai-Hulud|Sha1-Hulud|Hades|Miasma|niagA oG eW"; "i"))'
For an organisation, check its members' personal accounts, since that is where the worm creates the repositories. This loop uses GitHub search, which finds the forward description and depends on the search index. Run the command above for an exact answer on any account it flags.
ORG=YOUR_ORG_NAME gh api --paginate "orgs/$ORG/members" --jq '.[].login' | while read -r u; do gh search repos --owner "$u" --match description "Shai-Hulud" --limit 1000 --json fullName,createdAt --jq '.[] | "\(.createdAt) \(.fullName)"' done
We tested both. Pointed at this account, the first returned all 663 uploads; pointed at our own, it returned nothing. The second runs in bash and zsh and finds this account's uploads.
For a repository checkout, our CLI's agents scan reads the worm's autorun files without running them. Version 1.4.76 on PyPI reports them as critical and exits 1: xyz code-scan agents . --no-upload. It checks a checkout. It does not look at an account's repositories.
Clean up in this order
Revoking the stolen token first can trigger the token monitor, which deletes the home directory. Remove it before you touch any token.
Match the upload times against the laptops, servers and CI runners that hold your tokens.
Take it off the network, or stop the runner, so it cannot upload again or receive new commands.
~/.local/bin/gh-token-monitor.sh, ~/.config/gh-token-monitor/ and its systemd user service or macOS LaunchAgent. On Windows, its scheduled task and %LOCALAPPDATA%\gh-token-monitor\monitor.ps1.
The kitty-monitor service and ~/.local/share/kitty/cat.py, plus SessionStart hooks in ~/.claude/settings.json and in any repository you open.
GitHub tokens first, then npm, cloud, SSH and anything else the machine could read. Check every package the account can publish.
They hold your encrypted data. Treat whatever was on the machine as already copied.
ls -la ~/.local/bin/gh-token-monitor.sh ~/.config/gh-token-monitor ~/.local/share/kitty/cat.py 2>/dev/null ls ~/Library/LaunchAgents 2>/dev/null | grep -E 'gh-token-monitor|kitty-monitor' systemctl --user list-unit-files 2>/dev/null | grep -E 'gh-token-monitor|kitty-monitor' grep -n -E 'setup|index.js' ~/.claude/settings.json 2>/dev/null
Indicators
These are known public indicators of this worm family, with their sources. None is new to this post.
| Type | Indicator | Source |
|---|---|---|
| Dead-drop repositories | ||
| Description | Shai-Hulud: Here We Go Again | SafeDep, The Hacker News (October build) |
| Description, reversed | niagA oG eW ereH :duluH-iahS | StepSecurity, Corgea (May) |
| Repository name | ^[a-z]+-[a-z]+-[0-9]+$ | Two Dune words and a number (StepSecurity) |
| Upload file | results/results-<timestamp>-<n>.json | StepSecurity (June) |
| Command and control | ||
| Domain | t[.]m-kosche[.]com | May and September builds (Corgea) |
| Domain | iseekaigogo[.]com | October tensorlake build (SafeDep, The Hacker News) |
| On the infected machine | ||
| Token monitor | ~/.local/bin/gh-token-monitor.sh, ~/.config/gh-token-monitor/ | Deletes the home directory on token revocation (SafeDep) |
| Token monitor, Windows | %LOCALAPPDATA%\gh-token-monitor\monitor.ps1 | SafeDep |
| Persistence | ~/.local/share/kitty/cat.py, kitty-monitor service | Corgea |
What we did
We reported the account to GitHub on 20 October and asked them to disable the dead-drop repositories and tell the owner. We are not naming the account, linking to it, or listing its repositories. Its owner is a victim, and anyone who can read this can find the uploads.
We are not the only ones looking. Since 9 October, an independent researcher has been opening issues on accounts in the same state, such as this one, which has since been closed.
MappingMITRE ATT&CK
References
- CyberXYZPublic repository metadata, GH Archive records and hourly-check findings for one victim account (checked 22:33 UTC on 20 October)
- CyberXYZThe long tail of Mini Shai-Hulud: 24 more repositories the first reports missed (20 Oct 2026)
- StepSecurityShai-Hulud: Here We Go Again. Mass npm Supply Chain Attack Hits the AntV Ecosystem (19 May 2026)
- CorgeaMini Shai-Hulud npm worm: the AntV wave (May 2026)
- StepSecurityMiasma npm Supply Chain Attack: Self-Spreading Worm via Phantom Gyp (3 Jun 2026)
- SafeDeptensorlake 0.5.144 npm Compromise Ships Mini Shai-Hulud Malware (8 Oct 2026)
- The Hacker NewsTensorlake npm Package Compromised to Deliver Shai-Hulud Credential-Stealing Worm (8 Oct 2026)
- GitHub"Your account is creating Shai-Hulud exfiltration repos", an independent researcher (9 Oct 2026)
- MITRET1567.001 Exfiltration to Code Repository