CriticalSupply chainMonitoring

actions-cool/issues-helper and maintain-one-comment came back online still carrying Mini Shai-Hulud malware

Hijacked actions-cool/issues-helper and maintain-one-comment were re-enabled on 16 Sep 2026 with every tag still malicious. Remove them and rotate CI secrets.

Published
Updated
Fixed in
No fixed release. All tags pointed to malicious commits; GitHub blocked both repositories again on 24 September 2026
Exploitation
Yes. SafeDep found six repositories reinfected between 20 and 24 September 2026

What happened

On 18 May 2026, during the Mini Shai-Hulud campaign, an attacker moved all 53 tags of actions-cool/issues-helper and all 15 tags of actions-cool/maintain-one-comment to new malicious commits. The commits were made between 19:10 and 19:31 UTC, carry the message Build action for <tag>, list the author as Jinke Li, and are unsigned (SafeDep). GitHub disabled both repositories on 19 May (Socket).

  • 16 September 2026: both repositories became reachable again, some time between 09:09 and 16:16 UTC. The tags had never been restored, so every tag-pinned workflow ran the payload on its next run (Socket; The Hacker News).
  • 20 to 24 September: SafeDep found six repositories reinfected through issues-helper: jd-opensource/micro-app, MaaXYZ/MaaFramework, ant-design/pro-components, Moonofweisheng/wot-design-uni, vbenjs/vben-admin-thin-next and nineaiyu/xadmin-client. Five of the triggers were issue bots that run daily or on issue events (SafeDep).
  • 24 September: GitHub blocked both repositories again. The GitHub API now returns “Repository access blocked” with reason tos, timestamped 23:51 UTC that day (GitHub API).

Socket’s example: tag v2.2.1 of issues-helper resolves to commit a0c53dd42fc842d2f9276c5a1d4f9a26abe8713d (Socket).

What the payload does

All details from SafeDep unless stated.

  1. The malicious action.yml installs Bun with oven-sh/setup-bun and runs bun run $GITHUB_ACTION_PATH/index.js before calling the real action, so the step still passes (Socket).
  2. It steals CI secrets and sends them to t.m-kosche[.]com/api/public/otel/v1/traces.
  3. It reads a ghs_ token from Runner.Worker memory and commits files back to your repository through the GraphQL API. GitHub shows these commits as verified and authored by github-actions[bot]. The commit message can copy the parent commit’s message.
  4. The committed files make the attack jump to developers: .claude/settings.json adds a Claude Code SessionStart hook that runs node .claude/setup.mjs, and .vscode/tasks.json runs the same command when the folder opens. setup.mjs downloads Bun 1.3.14 and runs .claude/index.js.
  5. On a developer machine (not on CI) a kitty-monitor installer sets up persistence and a token monitor. A wiper runs rm -rf ~/; rm -rf ~/Documents if the stolen GitHub token starts returning HTTP 40x, among other triggers.
  6. On runners with passwordless sudo, it adds 127.0.0.1 entries for stepsecurity.io domains to /etc/hosts.

Am I affected?

Find references in every branch you build from:

bash
grep -rnE 'actions-cool/(issues-helper|maintain-one-comment)@' .github/workflows/

Any tag reference (@v1, @v2.1.1, @v2.2.0, @v2.2.1, @v3 and so on) that ran after 16 September 2026 executed the payload. Since 24 September the repositories are blocked, so those steps now fail at “Set up job”. Socket suggests looking in run history for jobs that started succeeding after a long run of “Set up job” failures, or whose duration jumped from seconds to minutes (Socket).

Look for the files the payload commits, in the working tree and in history:

bash
ls -la .claude/setup.mjs .claude/index.js 2>/dev/null
grep -n 'setup.mjs' .claude/settings.json .vscode/tasks.json 2>/dev/null
git log --all --since=2026-09-16 --format='%h %an %ad %s' -- .claude/ .vscode/tasks.json

Check for the exact payload blobs SafeDep published (index.js and setup.mjs):

bash
git rev-list --all --objects | grep -E '^(2931c1be43b0d04174636ddbff54963aec92bdeb|0bbd3d17062ded7c8159ffe22d0a4f3a85e4823e) '

On developer machines that opened an affected repository, look for persistence:

bash
ls -la ~/.local/share/kitty/cat.py ~/.local/bin/gh-token-monitor.sh 2>/dev/null
ps aux | grep -E 'kitty-monitor|gh-token-monitor' | grep -v grep

Search DNS, proxy and runner egress logs for t.m-kosche.com.

What to do now

  1. Remove both actions. No clean tag exists and the repositories are blocked. Socket and The Hacker News say only a full commit SHA from a release made before 18 May 2026 is safe; neither publishes one, and the upstream history cannot be browsed while GitHub blocks the repositories (Socket; The Hacker News). Replace the step with a maintained alternative or a short gh script.
  2. Rotate secrets available to any workflow that ran a tag reference on or after 16 September 2026, and review what that job’s GITHUB_TOKEN could do (Socket).
  3. Revert the hook commits. Delete .claude/setup.mjs, .claude/index.js, the SessionStart hook in .claude/settings.json and the task in .vscode/tasks.json from every branch. Do not trust the “verified” badge or the message on those commits.
  4. Isolate developer machines before revoking tokens. If kitty-monitor or gh-token-monitor is present, revoking the stolen GitHub token can fire the wiper described above. Take the machine offline and back it up, then remove the persistence, then revoke.
  5. Check /etc/hosts on self-hosted runners for stepsecurity.io entries pointing to 127.0.0.1, and rebuild any runner where you find them.

Why this matters

A tag is not a version. These tags had pointed to malware for four months. GitHub taking the repository down hid the problem, and bringing it back re-armed every tag-pinned workflow at once, with no new release for anyone to notice.

Sources