On 20 October 2026, 18:30 to 18:37 UTC the worm's files were still on 16 branches of alibaba/hooks, 24 branches of metersphere/metersphere (39 of its 44 counting an older June build of the same worm) and 41 branches of jdf2e/nutui-react. Their default branches are clean. Do not open a checkout of any other branch in Claude Code, VS Code or Cursor until you have checked it. If you already have, treat that machine as compromised. Remove the persistence first, then rotate credentials: this worm can wipe your home directory when its stolen token is revoked. We did not check whether any npm release was built from an infected branch.
Summary
- What: every tag of
actions-cool/issues-helperandactions-cool/maintain-one-commenthas pointed at the Mini Shai-Hulud payload since 18 May 2026. Workflows that called them by tag while GitHub allowed it (18 to 19 May, and 16 to 25 September) ran the worm, which commits Claude Code and VS Code autorun files to up to 50 branches. - Who found it: Socket, SafeDep and Aikido reported the campaign in September, and SafeDep listed six infected repositories. We did not discover this campaign.
- What is new here: 24 more repositories carrying the worm that no public report names, from 74 days of GitHub Archive data and a sweep of workflow files, plus four projects whose workflows still call the hijacked action by tag.
- Status on 20 October: element-plus deleted all 27 infected branches after our report. 23 of the 24 still carry the worm, on 544 branches in all.
Who reported this first
Socket showed that GitHub re-enabled both actions on 16 September with their May tags still pointing at malicious commits, and recorded that GitHub disabled them again on 25 September. SafeDep listed six repositories that received the worm's hook files between 20 and 24 September: jd-opensource/micro-app, MaaXYZ/MaaFramework, ant-design/pro-components, Moonofweisheng/wot-design-uni, vbenjs/vben-admin-thin-next and nineaiyu/xadmin-client. Aikido opened issue #9704 on pro-components the morning it was hit, and our earlier post reconstructed that run from the repository's own logs. The older June build of the worm that we also found on metersphere was reported first by StepSecurity and then by SafeDep (see below).
SafeDep built its list with GitHub code search and said it could miss repositories. The gap turned out to be structural. In each of the four infected organisation projects we name below, the default branch is clean today and the worm sits only on other branches, which GitHub code search does not index.
We reported every project we name here before publishing. Personal forks and repositories we are still reporting appear only as counts.
What is newWhat the first reports did not name
22 repositories in GitHub Archive
70 worm push bursts landed in 25 repositories between 20 and 24 September. Only 3 of the 25 appear in the public reports.
element-plus, since 19 May
27 branches written in the first wave in May. We found them by checking the upstream of an infected fork. Fixed on 20 October.
alibaba/hooks, since 19 May
16 branches carry the worm, and two of its issue workflows still call actions-cool/issues-helper@v3 by tag.
Four more still wired to it
umi, dumi, G6 and ant-design-charts have no worm files, but their workflows still call the hijacked action by tag. Three had a successful run while it was live.
Two generations on metersphere
20 branches also carry the worm's June build, on commits forged in real developers' names. On 5 of them the September worm landed on top.
Most of it is still there
On 20 October 23 of the 24 still carried the worm. 17 of the 19 personal forks have it on their default branch.
How we looked
GH Archive publishes every public GitHub event, hour by hour. We read all 1,776 hourly files from 1 August to 13 October 2026, 161,819,014 events and 36.4 GB compressed, and looked for the shape the worm leaves: github-actions[bot] pushing three or more branches of one repository within 15 seconds. Plenty of ordinary automation makes that shape too: on its own it was the worm only 0.66% of the time.
We checked each burst without downloading anything that could run. We asked raw.githubusercontent.com only for the HTTP status of .claude/settings.json and .vscode/tasks.json at the pushed commit. Then we fetched the commit objects alone, with no trees or files, to read the author and message. A burst counted when both files were present and the commit was a github-actions[bot] commit reusing its parent's message, which is how the payload writes.
Data table
| Stage | Count |
|---|---|
| GH Archive events, 1 Aug to 13 Oct | 161,819,014 |
| pushes by github-actions[bot] | 11,584,131 |
| bursts: 3+ branches of one repo in 15 s | 10,546 |
| bursts with both worm configs at the pushed commit | 84 |
| ... and a bot commit reusing its parent's message | 70 |
70 bursts in 25 repositories passed, 329 branch pushes in all. Every one falls between 20 Sep 02:52 and 24 Sep 21:12 UTC, inside the window when GitHub had re-enabled the actions. The hunt found none outside it.
Data table
| Group | Bursts | Branches pushed | First (UTC) | Last (UTC) |
|---|---|---|---|---|
| metersphere/metersphere | 1 | 4 | 21 Sep 00:14 | 21 Sep 00:14 |
| jdf2e/nutui-react | 1 | 10 | 21 Sep 07:31 | 21 Sep 07:31 |
| 19 personal forks and 1 repository we are still reporting | 63 | 297 | 20 Sep 02:52 | 24 Sep 21:12 |
| 3 repositories SafeDep or Socket named | 5 | 18 | 20 Sep 16:16 | 24 Sep 07:03 |
GH Archive is a partial feed. Two of SafeDep's six repositories, pro-components among them, have no events in it for their worm runs, and a third shows a single push, so the hunt found only three of SafeDep's six. Every count in this post is a floor.
Two more repositories came from outside GH Archive. One of the 22 is a personal fork of element-plus, and checking its upstream found element-plus/element-plus itself, infected in May. A separate sweep of the workflow files of repositories behind packages we track found alibaba/hooks, also infected in May, and the four projects still wired to the action.
FindingsWhere the worm is, and who has cleaned up
Branch counts below compare .claude/settings.json and .vscode/tasks.json at every branch head with the worm's files by SHA-256. Workflow counts are lines on the default branch that call actions-cool/issues-helper@ or actions-cool/maintain-one-comment@ by tag; the pinned -backup forks are not counted. We re-checked everything on 20 October 2026, 18:30 to 18:37 UTC, logged out, with git ls-remote and raw.githubusercontent.com.
| Repository | Found by | Worm branches, 17 Oct | Worm branches, 20 Oct | Calls the action by tag, 20 Oct | Report |
|---|---|---|---|---|---|
element-plus/element-plus | Upstream of an infected fork | 27 of 100 | 0 of 74 | 0 (uses the pinned -backup fork) | Emailed 17 Oct. Fixed 20 Oct |
alibaba/hooks | Workflow sweep | 16 of 28 | 16 of 28 | 3 | Reported privately 17 Oct |
metersphere/metersphere | GH Archive | 24 of 44 | 24 of 44 (39 with the June build) | 0 | Reported privately 17 Oct |
jdf2e/nutui-react | GH Archive | 41 of 49 | 41 of 49 | 2 | Team address bounced; maintainers emailed 17 Oct; no reply |
umijs/umi | Workflow sweep | 0 of 276 | 0 of 275 | 3 | Reported privately 17 Oct |
umijs/dumi | Workflow sweep | 0 of 23 | 0 of 23 | 2 | Reported privately 17 Oct |
antvis/G6 | Workflow sweep | 0 of 17 | 0 of 18 | 9 | Reported privately 17 Oct |
ant-design/ant-design-charts | Workflow sweep | 0 of 19 | 0 of 19 | 9 | Added to Ant Design's existing advisory |
| 19 personal or abandoned forks | GH Archive | 416 branches (14 Oct) | 416 branches; 17 default branches | not counted | Reported to GitHub 17 Oct |
| 1 more organisation repository | GH Archive | not yet reported | 47 of 78 | not counted | Being reported |
Data table
| Repository | 17 Oct | 20 Oct |
|---|---|---|
element-plus/element-plus | 27 | 0 |
jdf2e/nutui-react | 41 | 41 |
metersphere/metersphere | 24 | 24 |
alibaba/hooks | 16 | 16 |
element-plus/element-plus: fixed
The worm wrote 27 branches of element-plus, among them next, generic and perf/table, in two runs about 30 seconds apart at 00:07 UTC on 19 May 2026, the day GitHub blocked the actions. The maintainers pinned every action to a commit the same day, which closed the entry point, but the branches stayed. The project has no security policy and private reporting was off, so on 17 October we emailed the maintainers listed on npm. They deleted all 27 branches, and our re-check at 16:10 UTC on 20 October found none of the remaining 74 infected. Thank you to the element-plus maintainers for the quick fix, and for letting us name the project.
alibaba/hooks: 16 branches since May, and still wired to the action
16 of 28 branches carry the worm, written between 00:28 and 00:31 UTC on 19 May 2026. The default branch, master, is clean. On 20 May the maintainers removed the action from one issue workflow, but two others still call actions-cool/issues-helper@v3 by tag, in three places. Today only GitHub's block on the action stops those runs. We reported it privately on 17 October. Nothing had changed when we re-checked on 20 October.
Data table
| Item | From (UTC) | To (UTC) | Exposure |
|---|---|---|---|
element-plus | 2026-05-19 00:07:09 | 2026-10-20 16:10:00 | 154 d 16 h |
alibaba/hooks | 2026-05-19 00:28:59 | not yet | still there on 20 Oct, 154 d 18 h |
metersphere | 2026-05-19 00:29:30 | not yet | still there on 20 Oct, 154 d 18 h |
nutui-react | 2026-09-21 07:31:16 | not yet | still there on 20 Oct, 29 d 11 h |
19 personal forks | 2026-09-20 02:52:22 | not yet | still there on 20 Oct, 30 d 15 h |
pro-components | 2026-09-24 03:43:58 | 2026-10-15 02:06:09 | 20 d 22 h |
metersphere/metersphere: two generations of the worm on the same branches
The actions-cool worm first wrote metersphere's dev branch at 00:29 UTC on 19 May 2026. It came back on 21 September, when GH Archive shows github-actions[bot] pushing to four branches within 17 seconds at 00:14:30 UTC. On 20 October, 24 of the 44 branches carried its files, including dev and every v1 release branch. The default branch, v3.x, is clean, and no workflow on it uses actions-cool today.
20 branches also carry an older generation: the June 2026 build of the same worm kit, known as Miasma, which StepSecurity reported first on 3 June. Its hooks run .github/setup.js, and it also plants .gemini/settings.json and .cursor/rules/setup.mdc. SafeDep documented how it forges commits under a maintainer's own name, and its list of infected repositories includes metersphere/helm-chart, but not metersphere/metersphere.
What we add is small. The June build sits on 20 branches of metersphere/metersphere itself. It arrived in June 2026, not through the CI action. Each commit copies its parent's author name, email and date, appends [skip ci] to the parent's message and is unsigned, so the history shows the name and email of a real maintainer, on commits dated as far back as December 2021. On 5 branches, v1.15 and v1.17 to v1.20, the September worm then landed on top: two generations, four months apart, arriving by different routes. Counting both, 39 of the 44 branches carry one worm or the other, and all 39 are in our private report to the maintainers, filed on 17 October.
jdf2e/nutui-react: 41 branches, no reply yet
GH Archive saw one burst, 10 branches in 37 seconds at 07:31 UTC on 21 September; on 20 October, 41 of 49 branches carried the worm. The default branch, feat_v4.x, is clean, but two of its issue workflows still call actions-cool/issues-helper@v3 by tag. The public run list shows a successful run of one of them in each window when the action was live. The project has no security policy and private reporting is off. Its team address bounced on 17 October, so we emailed the maintainers who publish its npm package. We have had no reply.
Four projects still wired to the hijacked action
The workflow sweep found four projects with no worm files on any branch whose default-branch workflows still call the hijacked action by tag:
antvis/G6andant-design/ant-design-charts: nine lines each, inmanage-labeled.ymlandmark-duplicate.yml, at@v3and@v3.6.0.umijs/umi:maintain-one-comment@v3once andissues-helper@v3twice, inissue-checker.yml.umijs/dumi:issues-helper@v1twice, inissue-reply.yml.
Three of them had a successful run of the affected workflow while the action was live. umi's Issue Checker (run 3268) and G6's Mark Duplicate Issue (run 1545) ran between 16 and 25 September, and dumi's Issue Reply (run 1381) on 18 or 19 May. A successful run does not prove the payload ran, and no worm files reached their branches. Only the run logs can settle it, so we recommended rotating any secret those workflows could reach. ant-design-charts shows no run in either window. If GitHub re-enables the actions again, the next issue event runs the payload in all four. We reported umi, dumi and G6 privately on 17 October, and added ant-design-charts to Ant Design's existing private advisory. G6's npm package, @antv/g6, was among those compromised in the separate May npm wave; this finding concerns its GitHub workflows.
19 personal and abandoned forks
19 of the 22 repositories we found in GH Archive are personal forks: 12 of ant-design and seven of other projects. They kept the upstream's issue workflows, and most look abandoned. The ant-design forks were written in the same minutes, at 02:52 and 05:56 UTC on 20 September and 07:53 and 11:06 UTC on 22 September, which fits a scheduled workflow they share. On 20 October all 19 still carried the worm, on 416 branches in all, and in 17 of them the default branch is infected. None has a security contact or open issues, so we reported them to GitHub on 17 October. We do not name personal accounts.
Two more we are still reporting
We are still reporting two more organisation repositories. One carries the worm on its branches and is counted in the 24. The other is not exposed. We will name neither until the owners have been told.
Exfiltration repositories
The payload falls back to exfiltrating through public repositories it creates with a stolen token, under fixed descriptions such as the reversed niagA oG eW ereH :duluH-iahS that Corgea documented in May. The same hunt matched 866 new repositories under 13 accounts whose whole description is one of the worm's markers, created between 4 August and 13 October across several waves. One account alone holds 767, created between 20 and 30 September. We did not open them, and we do not name the accounts: they belong to victims.
Why the worm outlived the clean-up
- Disabling the action stops new runs, not old commits. element-plus and alibaba/hooks were written early on 19 May, the day GitHub blocked the actions, and kept the files for five months.
- The fixes went to the entry point. element-plus pinned its actions the same day, and alibaba/hooks removed the action from one workflow the next day. Neither removed the branches the worm had already written.
- The worm writes to branches nobody watches. It pushes to up to 50 branches with the job's token. Here it sits on release lines, Renovate branches and old feature work. Code search indexes only the default branch, and branch protection and review usually centre on it too.
- Forks run their upstream's automation. Abandoned forks kept scheduled issue workflows that called the action, so they ran the payload in September with nobody watching.
- A commit's author proves nothing. On metersphere, the June build sits in commits that carry a real maintainer's name and email, with dates as old as 2021. Check every branch for the files, whoever the history says wrote them.
- A tag is a moving pointer. Every workflow line we found that calls the action uses a tag such as
@v1,@v3or@v3.6.0, and every tag of the action was moved.
What we run now
The two checks behind this hunt went into our hourly GH Archive pipeline on 19 October. One looks for the burst shape and verifies each burst the same way, with HTTP status checks and commit metadata only. The other flags any new repository whose whole description is one of the worm's exfiltration markers. On the hunt window, a burst with both files at the pushed commit was the worm 83% of the time (70 of 84). Adding the copied-message check kept 70 of 70, but that figure is partly circular, since the same evidence confirmed them. The independent check is timing: all 70 fall inside the window when the actions were live. Findings go to our analysts for review. They do not alert customers on their own.
A second job reads the workflow files of repositories behind the packages we track and flags any that call a known-compromised action. On 17 October it flagged alibaba/hooks, ant-design-charts and G6 on its own, with eight HIGH findings.
IndicatorsIndicators of compromise
| Type | Indicator | Context |
|---|---|---|
| GitHub Actions | ||
| Action | actions-cool/issues-helper, every tag | All tags moved to malicious commits on 18 May 2026 (SafeDep: 53 tags); repository disabled by GitHub |
| Action | actions-cool/maintain-one-comment, every tag | Same campaign (SafeDep: 15 tags); repository disabled by GitHub |
| Action ref | issues-helper@v2.2.0 = 896379edfaac994ff214a3097c6c82e21be16066 | Resolved in the pro-components run (CyberXYZ, from the run log) |
| Action ref | issues-helper@v2.2.1 = a0c53dd42fc842d2f9276c5a1d4f9a26abe8713d | Socket |
| Action ref | issues-helper@v3 = 147337a919d9 | Malicious tag commit (SafeDep) |
| Worm files in this campaign (SHA-256) | ||
.claude/index.js | 26bc468790d3fa35c0e84423165fcf555bd4da6b5fd5f6d5b349262bd9f2b8aa | Payload, 500,143 bytes |
.claude/setup.mjs, .vscode/setup.mjs | 2be36c46d3f421bbd89bcb94997afb85020a672d82b64114637741411d7fc919 | Bun loader, same file twice |
.claude/settings.json | 9566275be80af10b8c6be1d47bfcfdbe5590f472b1a9abd85bad24e0a9a7a891 | SessionStart hook: node .claude/setup.mjs. Re-infected branches carry a second hook in the same file |
.vscode/tasks.json | 927387d0cfac1118df4b383decc2ea6ba49c9d2f98b47098bcbcba1efc026e1f | runOn: folderOpen |
| The same files in the August keyv commit (SHA-256) | ||
.claude/settings.json | 14eb4ce01dd4307759887ff819359b70d7d9ff709ecde039a5abc1aac325b128 | keyv build |
.claude/setup.mjs, .vscode/setup.mjs | fd3ca4007b225fdf8de7af4345a19179d5efa8c4bb9205f88cda806e5684b1eb | keyv build |
.claude/math_init.js | 9fc2570b7cef51c1b8df116d144d11ff4096357be7d2c4c6367cfc2509cf1bcc | keyv build payload |
| The June build on metersphere (SHA-256) | ||
.github/setup.js | c48b77e30d72bc3295ec9736996834fe4927dcd499332e75d06c09884052a4e7 | Payload runner, 4,646,584 bytes. Re-wrapped on every run, so other copies hash differently |
.cursor/rules/setup.mdc | cf9e7b24b756df81fbae37941cb41c8de6beaf848fafa332a10ea4490c4fd260 | Cursor rule that runs the payload (StepSecurity, SafeDep; our analysis) |
| Network and markers | ||
| Domain | t[.]m-kosche[.]com | Exfiltration, path /api/public/otel/v1/traces (Corgea, May 2026) |
| Repo description | niagA oG eW ereH :duluH-iahS | Fallback exfiltration repositories (Corgea) |
| On developer machines | ||
| Persistence | ~/.local/share/kitty/cat.py, kitty-monitor service | Remote-command backdoor (Corgea; our decode) |
| Dead man's switch | ~/.local/bin/gh-token-monitor.sh, ~/.config/gh-token-monitor/ | Wipes the home directory on token revocation (SafeDep; our decode) |
| State file | /var/tmp/.gh_update_state | Our decode |
Check every branch, then the machine
The default branch tells you nothing here. List the worm's config files on every branch of a clone, without checking any branch out:
Any branch that lists .claude/settings.json, .gemini/settings.json, .vscode/tasks.json, .cursor/rules/ or .github/setup.js needs a look. Read them with git show, and look for a SessionStart hook or a folderOpen task that runs a script. If you find the worm and might have opened that branch, check the machine:
Disconnect the machine first. Remove gh-token-monitor before you revoke any GitHub token, then remove kitty-monitor, then rotate GitHub, npm, cloud and SSH credentials from a different, clean machine.
Scan a checkout before you open it
Our CLI reads these files without running them. We ran the released version, 1.4.75 from PyPI, signed out and with uploads off, against a shallow clone of one infected alibaba/hooks branch, chore/node_version. We never opened that clone in an editor or agent, and we deleted it afterwards.
code-scan agents reads Claude Code and Gemini settings, VS Code folder-open tasks and agent instruction files. It matched all five worm files by hash and flagged both autorun entries:
Each finding says what to do. The first reads: “.claude/index.js is byte for byte a known Mini Shai-Hulud file (sha256 26bc468790d3fa35..., seen as .claude/index.js in ant-design/pro-components@1bc4049d). Do not open this checkout in an AI agent or editor.”
code-scan ci on the same branch named the hijacked action in all five places its issue workflows use it:
Both commands exited 1. So did the thresholds our GitHub Action uses by default, --fail-on critical for the CI scan and --fail-on high for the agents scan. CyberXYZSecurity/depalert-action v1.3.0 runs both scans next to its dependency gate. Pin it by commit like any other action:
What it does not do:
- It scans the checkout in front of it, one branch at a time, and cannot see the others. In every organisation project here, that is where the worm sits. Run the branch loop above first.
- The known-file check matches the hashes we hold, including copies with Windows (CRLF) line endings, which we tested. The June build's files are not on that list, but the same version flags all five of them as critical through its hook, agent-rule, folder-open and payload checks. It does not detect the forged commit history.
- Its offline list of compromised actions names
actions-cool/issues-helperbut not yetmaintain-one-comment. On umi's workflow that line is reported only as an unpinned action, at high.
What to change
- Delete or clean the branches, all of them. List every branch with the loop above, not just the default. Delete the branches you no longer use, and revert the worm commit on the rest, which removes all five files.
- Remember what deleting a branch does not reach. GitHub keeps pull request refs (
refs/pull/N/head), which maintainers cannot delete, and forks keep their own copies. Ask GitHub Support to remove pull request refs that point at worm commits, and tell fork owners. - Pin every third-party action to a full commit SHA, and replace
actions-cool/issues-helperandmaintain-one-comment, for example withactions/github-script. Give each workflow an explicitpermissions:block: an issue bot needsissues: write, not write access to contents. - Rotate secrets. If a workflow called either action by tag and ran between 18 and 19 May or between 16 and 25 September 2026, rotate every secret and token that job could read. Check its log for a
setup-bunstep followed by a longbun run. - Treat agent and editor configuration as code. Review
.claude/and.vscode/tasks.jsonchanges in pull requests, settask.allowAutomaticTaskstooffin VS Code, and read a repository's hooks before you trust it.
MITRE ATT&CK
References
- CyberXYZGH Archive hunt (1 Aug to 13 Oct 2026), workflow sweep, tokenless re-checks and CLI runs (20 October 2026, 18:30 to 18:37 UTC)
- CyberXYZMini Shai-Hulud in ant-design/pro-components: six branches in seven seconds (15 Oct 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)
- SafeDepMiasma Worm Targets AI Coding Agents via GitHub Repos (5 Jun 2026)
- SafeDepMiasma Worm: Most Infected GitHub Repos Are Still Live (11 Jun 2026)
- Aikidoant-design/pro-components issue #9704: This repository is compromised (24 Sep 2026)
- SafeDepMini Shai-Hulud Is Still Infecting GitHub Repositories (24 Sep 2026)
- SocketRe-Enabled GitHub Actions Expose Thousands of Repositories to Mini Shai-Hulud (24 Sep 2026, updated 25 Sep)
- MITRES9043, T1195.001 Compromise Software Dependencies and Development Tools