Anthropic’s inference hooks let a security server allow or deny every Claude Enterprise prompt and tool call before the model runs. Metano is now that server. It works on any device, with nothing installed.
Varun Anand
Most reporting on the Shai-Hulud worms covers the moment of attack: a poisoned package, a hijacked build tool, a rush to revoke stolen tokens. This post is about what is happening now.
As we write, computers infected with the worm are still sending their owners’ secrets to GitHub. Since 21 October they have created 990 dead-drop repositories: public repositories holding the encrypted stolen data. The pace was about 86 a day until 30 October and has been about 47 a day since. The newest appeared at 07:45 UTC on 3 November. Based on the worm’s code, each upload holds what it collected from one developer’s computer or build server: GitHub and npm tokens, cloud keys and other saved secrets. We estimate that 100 to 200 infected computers are behind these uploads, sending again and again.
During the upload, instead of using the infected computer’s own GitHub token, the worm almost always uses a token stolen from another developer, passed between infected computers. When that token stops working, another infected computer notices this and shares its own, and the uploads carry on. Nobody manages this by hand.

How the worm works is already well documented, as are the return of the hijacked actions-cool GitHub Actions from 16 to 25 September and the poisoned tensorlake package on npm on 8 October. We don’t repeat any of that here.
Two things set this wave apart: almost no poisoned packages are behind it, and the uploads have run through shared tokens for weeks.
1. Almost no poisoned packages. The big earlier waves, in May and August, put many poisoned package versions on npm within hours (more than 160 on 11 May alone). This wave has had almost none of its own: the only one reported is tensorlake, on 8 October, and we found nothing linking it to the computers here. That could change quickly, because this version still carries code to republish a victim’s packages when it finds an npm token that can publish without a two-factor check. How and when these computers were infected is still open. Some may be old infections that were never cleaned up; others may come from the hijacked actions-cool actions in September, which returned the day before this chain of shared tokens started.
2. Uploads have run through shared tokens for weeks. The August and early-October waves were described as uploading under each victim’s own account. The public GitHub event archive suggests August already passed uploads from one account to the next within minutes, as shared upload accounts did in May and June. What is new is how long it has lasted: since 21 October, almost every upload has gone through one shared token at a time, and only two tokens have carried them.


When it runs, the worm also tries to steal the secrets stored in the victim’s repositories. It adds a GitHub Actions workflow that would copy them out, on a fake Dependabot branch that is deleted within about 10 seconds, too fast for an owner to notice. Unlike the uploads, which go through a shared token, this step uses only the infected computer’s own token, and only if that token has the workflow scope. So a push means the worm ran on that developer’s own computer, and the owners of the shared tokens are victims too.
In September and October, at least 12 repositories had this workflow pushed into them. GitHub’s repository activity view shows these pushes even after the branch is gone. The same workflow hit at least 30 repositories in the August wave too.
The stakes go beyond one developer. The September and October targets include projects whose workflows use signing keys and publishing passwords. With those, an attacker could ship a malicious update that users would install as genuine.

This is not part of the October wave, but it is still infecting developers. On 18 May, a hijacked GitHub Action in the sync workflow that forks of a popular open-source AI chat app inherit committed the May version of the worm into those forks, together with Claude Code and VS Code settings that run it when the repository is opened. We found it in 139 forks; 137 still carry it, 108 of them on their main branch. One fork owner’s computer ran it again on 1 November. If you own a fork of a repository whose workflows use actions-cool/issues-helper, run the fork check under “What to do now” before opening it.

Check whether your accounts hold dead-drop repositories. Run both lines for each developer account you are responsible for:
gh api -X GET search/repositories -f q='"Shai-Hulud: Here We Go Again" in:description user:LOGIN' --jq .total_count
gh api -X GET search/repositories -f q='"niagA oG eW ereH :duluH-iahS" in:description user:LOGIN' --jq .total_countReplace LOGIN with the account’s GitHub username. The second line checks the reversed description that earlier versions use.
Any result above zero means the worm ran with that account’s token, either for its owner’s own uploads or for other people’s. Zero does not mean clean: most infected computers upload through someone else’s token, so their owners’ accounts hold nothing.
Check whether the secret-stealing branch touched your repositories, even though it is gone:
gh api "repos/OWNER/REPO/activity?ref=refs/heads/dependabot/github_actions/format/setup-formatter" \
--jq '.[] | [.timestamp, .activity_type, .actor.login, .after] | @tsv'Replace OWNER/REPO with the repository’s owner and name, here and in the commands below. Empty output means GitHub has no record of that branch being pushed.
Do not approve Run Copilot workflows. List workflow runs waiting for approval and delete any you didn’t set up:
gh api "repos/OWNER/REPO/actions/runs?status=action_required" \
--jq '.workflow_runs[] | [.id, .name, .path, .head_branch, .created_at] | @tsv'Check forks you own for the planted files, on every branch:
for b in $(gh api "repos/OWNER/REPO/branches" --paginate --jq '.[].name'); do
gh api "repos/OWNER/REPO/commits?sha=$b&path=.claude/setup.mjs&per_page=1" \
--jq ".[] | \"$b \(.sha) \(.commit.author.name) \(.commit.author.date)\""
doneIf a token or computer is involved, disconnect the computer before revoking any token, because the worm wipes the user’s files when its stolen token is revoked. Then revoke the tokens and rotate every password and key that computer could reach. Deleting the dead-drop repositories alone does not stop the theft. If a branch carries the planted files, delete it before anyone opens it.
If you find dead-drops on someone else’s account, don’t report the account for suspension or revoke its token. Tell GitHub Security instead; suspending or revoking before the owner disconnects wipes their computer.
Restrict classic tokens. The worm uses only classic and OAuth GitHub tokens, never fine-grained ones, so restricting classic tokens in your organisation narrows what a stolen token can reach.
Treat AI-agent and editor settings as code. A command set to run when a Claude Code session starts, or when a folder opens in VS Code, runs with the developer’s full access. Check these files in any branch you didn’t write before opening the folder.
| What | What it looks like | Notes |
|---|---|---|
| Dead-drop repository | Public repository described as Shai-Hulud: Here We Go Again, holding results/results-<number>.json files; earlier versions use the reversed text niagA oG eW ereH :duluH-iahS | 990 created since 21 October and still online |
| Secret-stealing branch | dependabot/github_actions/format/setup-formatter created, pushed to and deleted within about 10 seconds by a user’s token | The vanishing pattern is the sign; the branch name is public |
| Workflow run waiting for approval | By github-actions[bot], signed by GitHub, reusing the previous commit’s message, adding .claude/index.js, .claude/setup.mjs, .vscode/setup.mjs, .claude/settings.json, .vscode/tasks.json | 18 May 19:00 to 19 May 00:30 UTC in the forks we checked |
| The worm file (May version) | .claude/index.js, 500,143 bytes, git blob 2931c1be43b0d04174636ddbff54963aec92bdeb | Also found in two repositories infected by automatic workflows in September |
| Sign in the workflow run log | A step using actions-cool/issues-helper taking over 10 seconds, plus an extra step that earlier runs did not have | Runs between 18 and 19 May, or 16 and 25 September |
What we saw directly: public GitHub information (repository search, file lists, commit details, workflow step timings, public events and repository activity), the public GH Archive event dataset, and public package-registry records. The upload counts, the secret-stealing commits, and the fork check all come from these.
What we read in the worm source code: how infected computers choose a token, and when they add the secret-stealing workflow, comes from reading the worm’s code. We never ran the worm and never opened or decrypted the stolen data.
Limits:
We reported these findings to GitHub on 2 November 2026 and privately notified the owners of the most exposed accounts before publication.

Japneet Singh
Head of Research
Japneet leads the Research team at Metano. Two decades in cybersecurity, one decade in AI x cybersecurity. Hands on practitioner, leading by example. Interested in applying AI to defensive and offensive security.
The latest news, technologies, and resources from our team.
Anthropic’s inference hooks let a security server allow or deny every Claude Enterprise prompt and tool call before the model runs. Metano is now that server. It works on any device, with nothing installed.
Varun Anand
Exposed LiteLLM gateways that still use the sample admin key will hand out API keys to anyone who asks. Each key is unique, so we could follow it to see who used it next.
Neelima Rustagi and Sonali Tyagi
An agent skill runs with everything the agent that loads it can do. New research from Metano MARS Labs, Purdue University and VulNow profiles more than 6,000 skills sourced from a couple of different marketplaces, to measure how much of that authority they put into play.
Japneet Singh
Metano is live on the Okta Integration Network. Tie every AI agent to its Okta identity, see what it does at runtime, and stop the agent and its access in one step.
Varun Anand
Operation Poetic Injustice: your LiteLLM gateway is somebody else’s command-and-control server.
Ratnesh Pandey, Japneet Singh, and Varun Anand
From broken authorization to skipped confirmations, Metano’s MCP research found one recurring problem: the control isn’t where the action happens.
Parth Shukla
Occasional updates, new content, and insights. No spam; unsubscribe anytime.