A GitHub Actions run has stopped before the runner starts. GitHub's systems have judged it suspicious enough to hold. The screen now needs a person with write access to decide whether it should execute.

That pause is a real security control. If the collaborator refuses, the job never receives a runner, a repository token or any secrets its configuration would have exposed. But the warning is not a verdict. GitHub calls the run potentially malicious, requires a review and hands the allow decision to an authenticated human session.

The hard part has moved. An authorised role must now answer a question the classifier did not: does this workflow belong here?

GitHub introduced the protection on 28 July. It applies automatically to certain held runs in public repositories on GitHub.com. A repository collaborator with write access must review and approve through an authenticated web session; only then does the workflow continue normally. At launch—and in GitHub's current public description—the protection does not cover private repositories or GitHub Enterprise Server.

GitHub has not published the signals, detection rate or false-positive rate behind the hold. So there is no evidence for either of the easy claims: that the feature catches every dangerous workflow, or that it is merely a decorative warning. The documented claim is narrower and useful. When GitHub classifies a run and holds it, execution waits.

A workflow file is executable authority

The YAML files under .github/workflows/ look like configuration. On an event such as a push, pull request or manual dispatch, they can start a runner, download actions and issue shell commands. A job also receives a short-lived GITHUB_TOKEN created for that job. Depending on configuration, it may receive repository or environment secrets and permission to request a cloud identity.

That makes a workflow change different from an inert setting. It edits the instructions that will run inside the build system's trust envelope.

GitHub's token documentation says the per-job token is an installation access token scoped to the repository. Its exact authority is configurable. The permissions guide warns that an action can reach the token through the github.token context even when a workflow does not explicitly pass it. GitHub therefore recommends giving the token only the permissions a job needs.

The important words are “a job needs.” A safe job with contents: read and no deployment secrets offers far less to steal than a release job holding registry credentials, write permission and a cloud role. The new hold can stop either job before execution when it fires. If the workflow is missed or approved, the permission design becomes the next boundary.

What 5,718 malicious commits were built to do

The attack class is not hypothetical. On 18 May, researchers at SafeDep found a campaign they named Megalodon after their malware analysis flagged a poisoned Tiledesk package. They traced the finding back to GitHub and searched for matching commit identities.

SafeDep counted 5,718 malicious commits to 5,561 distinct repositories between about 11:36 and 17:48 UTC—just over six hours. The commits used author names such as build-bot, auto-ci and pipeline-bot, paired with routine-sounding messages including “chore: optimize pipeline runtime.” TechRadar independently reported the findings four days later.

Those numbers need a boundary of their own. They count repositories that received a matching malicious commit, based on SafeDep's GitHub search. They are not 5,561 confirmed successful thefts.

The workflow code shows the intended path. SafeDep documented two variants. The mass version added a workflow named SysDiag that could trigger on pushes and pull requests. A targeted version replaced an existing Tiledesk workflow, renamed it Optimize-Build and used workflow_dispatch, leaving a dormant job that required a later manual or API trigger.

Both variants carried a base64-encoded shell payload. SafeDep's decoded analysis found code built to inspect environment variables, credential files, source trees, cloud metadata endpoints and the material needed to request OpenID Connect tokens. The payload then tried to send what it found to an external server. In the Tiledesk example, the application code was unchanged; the executable policy around the build had been replaced.

That distinction matters for the new hold. A malicious commit can exist in a repository without its payload having run. The consequential transition is from stored workflow to executing job. GitHub inserted the checkpoint immediately before that transition.

The hold cuts one branch of the attack path

The path can be reduced to five decisions:

StageThe question that matters
Repository changeWho or what was allowed to write the workflow file?
GitHub classificationDid the run match GitHub's undisclosed suspicious-workflow signals?
Held approvalDid an eligible collaborator inspect the provenance and executable diff?
Runner startWhich token permissions and secrets did the job receive?
ResponseCan exposed credentials be revoked before reuse?

When classification succeeds and approval is withheld, the chain ends before the fourth row. No runner starts. That is stronger than detecting exfiltration after the fact.

The protection does not reach backward and prove that the account which pushed the change was legitimate. It does not reach forward and reduce the permissions of an approved job. GitHub's own supply-chain defence summary makes the larger point: attacks chain weaknesses together, and no single security capability stops all of them.

The original diagram above is Nowpinion's reconstruction from GitHub's documented hold and Actions security model. It is not a screenshot of GitHub's classifier. The “not held” branch is deliberately absent from the main path because GitHub has supplied no public coverage data that would let us draw it to scale.

Write access proves authority, not intent

GitHub requires a write-access collaborator and an authenticated web session to approve. Those conditions rule out an anonymous click. They confirm that the platform recognises the account and that its role is permitted to make the decision.

They cannot answer three different questions: whether the account is under its owner's control, whether the approver is independent of the change, and whether the person understood what the workflow would execute.

That is not a criticism unique to GitHub. It is the nature of an approval gate. A signature can establish who authorised a decision without making the decision correct.

The Megalodon evidence sharpens the first question. SafeDep's traced commit had no linked GitHub author or committer identity and was pushed directly, which the researchers attributed to a compromised personal access token or deploy key. The feature announcement itself says recent attacks used compromised GitHub credentials to push malicious Actions workflows. A role remains authorised in GitHub's permission graph even if a valid credential has been stolen.

The article cannot establish that a compromised account approved a run in Megalodon, or that GitHub created the hold because of that campaign. Neither claim is documented. The campaign is evidence for the threat path: valid repository authority can be used to place executable workflow code. The approval gate is GitHub's documented intervention before execution.

The strongest setup therefore separates the writer from the approver where a project can. If the same identity can introduce the workflow and release a warning about it, the pause may be real while the second opinion is missing.

What survives a bad approval

Assume the warning is approved incorrectly. The next question is not whether the gate “worked.” It is what the job can do.

GitHub's secure-use reference says users with write access can read repository secrets and recommends granting the GITHUB_TOKEN the minimum required permissions, starting with read-only repository contents where possible. It also recommends auditing workflow and action source, rotating exposed secrets, protecting sensitive environments and pinning third-party actions to full-length commit hashes.

These controls affect different links:

  • an independent review can catch an unexpected author, trigger, permission change or encoded shell command;
  • a narrow token can stop a running job from writing releases or repository contents it does not need;
  • a protected environment can keep deployment credentials behind an additional approval;
  • fewer, short-lived secrets reduce what a runner can export and reuse;
  • a full commit hash prevents a referenced action tag from silently moving, although it cannot make the selected code trustworthy.

None is a substitute for the hold. The hold can prevent all job execution for a run it catches. The other controls reduce the chance or damage of the paths that remain.

The May campaign illustrates why “we use OIDC, so there is no secret to steal” is too comfortable. SafeDep found code intended to collect the request URL and token that a workflow uses to mint an OIDC identity. Short-lived credentials remove valuable static keys, but a malicious job may still abuse the identity it is legitimately permitted to request. The cloud-side trust policy and the job's id-token permission still matter.

Four questions before the click

GitHub's hold supplies time. A useful review spends it on four concrete checks.

Who caused this run? Trace the account, token, commit and event. A bot-like author name is not proof of automation, and a familiar account is not proof that its current credential is clean.

What changed in executable workflow code? Read the complete diff under .github/workflows/, including triggers, permissions, external actions and shell commands. Encoded content, a new outbound destination or a switch to workflow_dispatch deserves an explanation tied to an expected change.

What will the job receive? Check GITHUB_TOKEN authority, repository and environment secrets, OIDC permission, runner type and any credentials already present on a self-hosted machine. This is the likely blast radius if review is wrong.

Why must this exact run execute now? A legitimate unusual workflow should have an owner and a reason. If provenance is unresolved, deny the run, investigate the account and rotate credentials that may already have been exposed through another path.

Those questions do not certify safety. They make the handoff honest. GitHub has already contributed an automated judgement: suspicious enough to stop. The approver's job is not to overrule a machine reflexively. It is to decide whether the code, identity and requested authority form a story the repository's owners actually intended.

The new hold is valuable because it creates a moment in which that story can still be checked before the runner starts. The click is where the pause becomes protection—or permission.