P.K. SHARMA

Cyber security intelligence, AI governance, practitioner analysis

Disabling a repository is not removing the malware, and on 16 September the tags started working again

Two GitHub Actions compromised in May were disabled the next day and stayed unreachable for 120 days. The malicious commit was never removed, the release tags still pointed at it, and when the repositories came back, so did the payload.

By Parminder Kumar Sharma · · 6 min read

Editorial illustration for the briefing: Disabling a repository is not removing the malware, and on 16 September the tags started working again

One hundred and twenty days offline, and nothing was cleaned

Malicious content was introduced into two GitHub Actions on 18 May 2026, as part of the Mini Shai-Hulud campaign. GitHub's security team disabled both repositories the next day, which is a fast response by any standard.

The repositories stayed unreachable for 120 days. On 16 September they became accessible again, in a window Socket narrows to between 09:09 and 16:16 UTC.

The malicious commit was still there. The release tags still pointed at it. So every workflow that referenced either action by tag rather than by a pinned commit hash resumed executing the payload on its next scheduled or triggered run, inside the runner, with that workflow's token and secrets.

What this does not establish. It does not establish how many repositories actually ran it: Socket says plainly that it has not determined how many dependents reference either action by a mutable tag rather than a pinned hash, and neither has anyone else. It does not establish why the repositories became reachable again, because GitHub has not said. It does not establish that the accounts were re-compromised, since nothing new was pushed. And it does not establish current risk from these two specific actions, because both were disabled again on 25 September, so workflows referencing them now fail at job setup instead of running anything.

What it does establish is that a disable is a reachability control and not a cleanup, and that four months of safety rested on a setting somebody could change.

Why a tag is not a version

This incident is really about one line of YAML that almost every organisation writes the wrong way.

When a workflow says it uses an action at @v2.2.1, that is not a version in the sense of an immutable artefact. It is a tag, which is a pointer to a commit, and whoever controls the repository can move it. Pinning instead to the full commit hash names the exact content, and nobody can change what that hash refers to.

GitHub has recommended pinning to a full commit hash in its own hardening guidance for years. This is the failure mode that recommendation exists for, demonstrated end to end.

The execution path in the runner is ordinary: the runner downloads the action and runs its entry point, which in this case installs a runtime and executes an obfuscated payload. There is no exploit. The workflow did what it was told, using the identity it was given, which is why the compromise reaches the secrets rather than just the source.

A diagram in two parts. The first is a timeline: malicious content added on 18 May 2026, both repositories disabled the next day, 120 days unreachable with the malicious commit untouched, both reachable again on 16 September, and disabled again on 25 September. The second contrasts two ways a workflow can reference an action: by tag, a movable pointer that resolved to the malicious commit the moment the repository returned, and by full commit hash, which names the content itself.
Drawn from Socket's research of 25 September 2026.

The timeline

Dates from Socket's research, with elapsed time computed for this briefing

DateWhat happenedElapsed
18 May 2026Malicious content introduced into both actionszero
19 May 2026GitHub disables both repositories1 day
19 May to 16 SeptemberRepositories unreachable. Malicious commit and tags untouched120 days
16 September 2026Both reachable again, between 09:09 and 16:16 UTC120 days
20 to 24 September 2026Hijacked tags reported planting hooks in six popular repositories124 to 128 days
25 September 2026Both disabled again. Workflows now fail at job setup129 days

Two things in that table deserve separating.

The response to the original compromise was good. One day from malicious commit to disabled repository is faster than most ecosystems manage, and it stopped the campaign spreading through those two actions.

The response was also incomplete in a way nobody noticed for four months. Disabling made the content unreachable without making it harmless. The moment the reachability changed, every downstream workflow that had not been fixed in the intervening 120 days went back to where it was on 18 May.

What to do about it

These two actions are disabled again, so the immediate exposure is closed. The useful work is the general case, because the next repository to come back online will not be announced either.

Take this with you

In the order worth doing

  • Search every workflow file in your estate for references to these two actions, including in archived and rarely triggered repositories, because a workflow that runs monthly has had two opportunities.
  • If you find either one, rotate every secret that workflow could reach, and treat the runner as having executed untrusted code with those secrets available.
  • Pin every third party action to a full commit hash rather than a tag or a branch. This is the single control that would have made the re-enable a non event.
  • Add a check to continuous integration that fails the build when a workflow references a third party action by anything other than a full hash.
  • Review your dependency alerting: an action being disabled is visible, and an action becoming available again is not, so absence of an alert is not evidence of anything.
  • Treat a disabled upstream dependency as unresolved rather than closed, and record what you would do if it returned.
  • Where you can, restrict which actions are permitted to run at the organisation level, so an unknown third party action cannot execute at all.

The question this leaves

There is a temptation to make this a story about GitHub, and it mostly is not. GitHub acted in a day, and disabling a repository is a reasonable thing to do with a compromised one. Whether the malicious content should have been purged rather than hidden is a fair question for the platform, and the answer probably involves the fact that nobody wants a platform that rewrites history in other people's repositories.

The part that belongs to everyone else is the four months. For 120 days, thousands of workflows carried a reference to a repository that had been taken down for hosting malware, and nothing in their pipelines told them to fix it, because the reference was failing quietly rather than loudly. Safety came from the upstream platform's configuration, not from anything the downstream teams had done.

So the question, and it applies to every pipeline: how many third party actions do your workflows reference by a tag that somebody else can move, and if one of them were disabled tomorrow, would your build fail loudly enough for anybody to fix the reference?

Sources

  1. PrimaryThe primary research, used for the timeline, the re-enable window, the dependent count and the mitigationSocketaccessed 2026-09-25
  2. PrimaryGitHub's own hardening guidance, used for the standing recommendation to pin actions to a full commit SHAGitHubaccessed 2026-09-25
  3. Reported bySecondary coverage, used only to confirm the wider receptionThe Hacker Newsaccessed 2026-09-25

Share this briefing

Know someone who owns this problem? Send it to them.

Related briefings

The briefing, in your inbox

Practitioner analysis of cyber and AI security news. No vendor noise.

One email per briefing. Unsubscribe any time.