Aller au contenu
Français
medium

actions-cool/issues-helper: 53 tags point to a booby-trapped commit

Lire cet article en français

10 min read
Tag poisoning

On May 18, 2026, 53 tags of the GitHub Action actions-cool/issues-helper were rewritten in less than 3 minutes and 16 seconds to point to an imposter commit that exfiltrates CI/CD secrets from the memory of the Runner.Worker process. A second action from the same organization, actions-cool/maintain-one-comment, received the same treatment in the same window (15 tags in 39 seconds). Only workflows pinned to a full legitimate commit SHA are spared. This article describes the mechanism, the IOCs published by StepSecurity, and the immediate action to take if you use either of these actions.

What will you learn here?

This post gives you everything needed to assess and contain the incident:

  • Understand what an imposter commit is in a tag poisoning attack
  • Identify whether your workflows use one of the compromised actions
  • Detect the indicators of compromise on the runner side
  • Protect yourself through SHA pinning and block the payload's network egress
  • Harden your posture after the incident

Who is exposed to this attack?

Any repository that consumes actions-cool/issues-helper or actions-cool/maintain-one-comment through a tag is exposed, typically @v3, @v3.7.6, @v2. That is the default pattern when you copy an example from the GitHub Actions Marketplace: easy to write, fragile in reality. The defense rule, pin every action to the full commit SHA, stopped being an expert-only recommendation after the tj-actions/changed-files precedent of March 2025. Yet it is still massively ignored, and every new compromise reminds us why.

What exactly happened?

The attacker gained the ability to move the tags in the actions-cool/issues-helper GitHub repository. He generated one imposter commit per tag, each with a fake commit message in the style of "Build action for vX.Y.Z" that mimics the maintainer's convention, and re-pointed all 53 tags to these new commits, which are attached to no branch of the repository (orphan commits).

The tell is in the timing: the 53 imposter commits were all created between 19:10:24 and 19:13:40 UTC on 2026-05-18. The same operation was carried out 17 minutes later on maintain-one-comment, with 15 commits created in 39 seconds. A human does not type 53 handcrafted commits in 3 minutes: this is automation.

On the payload side, when a workflow executes the compromised action on a runner:

  1. Download of the bun JavaScript runtime into /home/runner/.bun/bin/bun.
  2. Read of /proc/<Runner.Worker PID>/mem from a child Python process. This Runner.Worker process is the one holding the decrypted secrets of the workflow.
  3. Filtering of the memory looking for "isSecret":true, then extraction of the authentication tokens (gh auth token, pipeline secrets).
  4. HTTPS exfiltration to t.m-kosche.com on port 443.

Sources: the full analysis and the IOCs are published by StepSecurity. The maintainers were notified through issue #11 of the repository.

Are you affected?

One grep at the root of each repository answers the question:

Fenêtre de terminal
grep -rE "actions-cool/(issues-helper|maintain-one-comment)" \
.github/workflows/ 2>/dev/null

Three possible outcomes:

  • No result: you do not use these actions. Keep reading for the right preventive reflexes.
  • Reference by tag (@v3, @v3.7.6, @v2, etc.): your workflow is compromised on the next run. Immediate action below.
  • Reference by SHA: check that the SHA is not one of the imposter commits. Every SHA in the list published by StepSecurity must be banned. If your SHA is not in it, it is probably legitimate; confirm by checking that it belongs to the default branch of the repository.

What should you do immediately?

Rotate first, clean up second: that is the order that matters.

Once the rotation is done, two options for what comes next:

  1. Remove the action entirely if it is not critical. That is the safest option as long as the maintainers have not regained control of the repository and published an official statement.

  2. Pin to the last legitimate SHA: the one from the master branch on the eve of the incident. Concretely:

    # BEFORE - vulnerable
    - uses: actions-cool/issues-helper@v3
    # AFTER - SHA of a legitimate commit from the master branch
    - uses: actions-cool/issues-helper@<SHA-of-master-pre-May-18-2026> # v3

    To retrieve a legitimate SHA, open the history of the repository's master branch on GitHub at a date prior to May 18. Do not take a SHA from a tag: all of them were hijacked.

If you use the StepSecurity Harden-Runner tool with egress block mode, the exfiltration to t.m-kosche.com is already blocked. That does not prevent the memory read but it blocks the leak of the secrets: defense in depth.

How do you audit your whole fleet in one command?

Checking by hand that every uses: of every workflow is pinned by SHA does not scale beyond a handful of repositories. That is exactly what Plumber does, a CI/CD compliance scanner that covers GitHub Actions and GitLab CI. Its ISSUE-104 control flags any action referenced by tag or by unpinned SHA, which is precisely the attack surface of tag poisoning:

Fenêtre de terminal
# At the root of a GitHub repository
plumber analyze --score

Typical output on a vulnerable workflow:

CRIT [ISSUE-104] Third-party actions must be pinned by commit SHA
.github/workflows/issues.yml:12
actions-cool/issues-helper@v3, mutable reference (tag)

Bonus: Plumber also maintains a database of action SHAs carrying CVEs (control ISSUE-703). As soon as the imposter SHAs published by StepSecurity land in that database, a workflow that had mistakenly pinned to one of them would be alerted as well. Run plumber analyze in a CI step to block any pull request that regresses on these controls; that is exactly what would have prevented the incident for disciplined consumers.

Which indicators of compromise should you look for?

On a compromised runner, you will find:

  • Presence of the bun binary in /home/runner/.bun/bin/bun when your workflow does not expect it.
  • Reads of /proc/<PID>/mem from a child python3 process, with tr/grep pipelines filtering on "isSecret":true.
  • Outbound HTTPS connection to the domain t.m-kosche.com on port 443.

This domain is now on the global Harden-Runner blocklist. If you manage your own network allow-list for runners, you can add it to your egress firewall rules.

Why does this attack repeat the same pattern?

Because the playbook works: this is the third time in two months that we observe the same modus operandi. An attacker takes control of a GitHub Actions repository, rewrites all the tags so they point to malicious code that steals secrets through the memory of Runner.Worker. Before actions-cool/, there was Trivy (twice) and KICS from Checkmarx. This is no longer an isolated incident, it is an industrialized playbook.

The target is always the same: popular actions that run with production secrets and that teams consume by tag, not by SHA. The defense is also always the same, and it is not negotiable:

GitHub itself acknowledges the problem: the GitHub Actions 2026 security roadmap announces a system of dependency lock files (the equivalent of go.mod/go.sum for workflows) that will freeze all direct and transitive SHAs. Public preview announced in 3 to 6 months; until then, manual discipline remains the only defense.

What should you remember?

  • Tag poisoning: an attacker who controls a repository can rewrite all the tags to point to malicious code. Users pinned by tag pick up the payload on their next run.
  • Runner.Worker memory: it is the process holding the decrypted secrets. Reading /proc/<PID>/mem is enough to extract them, no need to bypass GitHub Secrets.
  • Pinning to a legitimate SHA is the only reliable and free defense. Everything else (rotation, monitoring, allow-list) is a complement.
  • The pattern repeats: Trivy in March, KICS in April, actions-cool in May. Every month, a new popular action. Consider that the third-party actions in your .github/workflows/ must be pinned before the next wave, not after.
  • The workflow lock file is coming natively from GitHub during 2026: prepare your workflows in pinned-SHA mode now, you will save time at migration.

What are the next steps?