AL+ Email us: paul@alplustech.com

GitHub Actions: justify the trust before allowing the workflow

GitHub plans to block pull_request_target by default in public repositories. Review contributor code, permissions and metadata work before allowing exceptions.

Also in: Română

A failed automation run creates pressure to restore the green check. For a privileged GitHub Actions workflow, that pressure can hide the more consequential decision: which contributor-controlled inputs are allowed to influence work that holds authority over your repository.

GitHub's November 2 announcement moves planned default blocking of pull_request_target to December 2. As of November 8, it schedules temporary enforcement on November 9 and 16, from 16:00 to 18:00 UTC. Those are announced windows; this article does not establish their outcome. The right preparation is to justify each workflow's trust before granting an exception.

A policy decision and a code decision

The announcement applies to public repositories on GitHub Free, Team and Enterprise Cloud. Private and internal repositories, and GitHub Enterprise Server, are outside that announced scope. An applicable event policy can explicitly allow the event, including by workflow file. Evaluate mode provides information about runs that would be blocked. These are GitHub's stated policy boundaries, not a finding about any particular repository.

An event policy decides whether a workflow may start. A review of its code decides whether starting it is a sound choice. Moving from blocked to allowed answers only the first question.

Treat an exception as a small design record. Name the business task, the trusted code that performs it and the permission it requires. Then describe where contributor-controlled material enters. If that explanation is difficult to write, the workflow likely combines work with different trust requirements.

Metadata work has a different boundary

Consider an illustrative bot that labels a pull request based on changed paths. It needs permission to update labels. It does not inherently need to build the proposed application or install dependencies from the contributor's branch.

GitHub's security guide explains that pull_request_target uses the base repository's default-branch workflow and can access base-repository secrets and a token with elevated permissions. The dangerous step is executing untrusted code in that context. Merely checking out files and executing those files are distinct operations, though a later test or build can connect them.

For the label bot, the review should therefore follow data into actions. A pull request title is data, even when read by a trusted script. Keep it as data rather than constructing a shell command from it. Restrict which labels can be changed if that is all the task requires. A workflow that never builds contributor code still needs input handling and limited authority.

That is a more useful criterion than deciding that every use of this event is wrong. Some repository maintenance genuinely needs to act on the base repository. Its permissions should match that job, with an identifiable owner who can explain why they remain necessary.

Running tests changes the question

Now consider an illustrative test job that installs dependencies and runs a build from a fork. Those steps are execution of contributor-influenced material. A familiar test command does not make the code behind it trusted.

For ordinary fork checks, prefer an execution context designed for untrusted contributions, with the permissions and secret restrictions appropriate to that work. GitHub's guide contrasts the fork pull_request context with pull_request_target. Changing an event name alone still requires reviewing the remaining workflow and repository settings.

If an authenticated operation is necessary, identify its smallest input and separate it from building the contribution. The proposed split also needs scrutiny: consuming an artifact or script produced by untrusted work can reintroduce the same problem. A trusted later job should not assume a file is safe because a previous workflow uploaded it.

This recommendation has a cost. Separate jobs can make automation harder to maintain, and private dependencies may complicate ordinary tests. Those constraints deserve an explicit design choice. They do not establish that arbitrary contributor code should inherit repository secrets.

Checkout protection is another layer

GitHub's June 18 checkout announcement describes protection against common fork-head checkout patterns in privileged workflows. Its July 15 editor's note revises the supported-version backport date to July 20. The original body retains an older date, so reading the note matters.

That protection and the November event policy address different points in the chain. One concerns a checkout operation; the other concerns permission to start an event-triggered workflow. Neither makes every way of fetching and executing outside code safe. The June announcement explicitly describes gaps such as alternative fetch commands and other untrusted repositories.

For review purposes, trace execution beyond the named checkout action. Include helper scripts and dependency installation. Inspect the version actually pinned in the repository. An announcement about a supported release does not prove that a workflow pinned to an older revision has received it.

A narrow exception can be reasonable

The strongest objection to blocking everything is legitimate base-repository automation. Losing triage or a carefully designed authenticated check can consume maintainer time and delay contributions. Preserving those uses after review is a reasonable outcome.

The exception should identify the specific workflow, the reason for its permissions and the inputs it refuses to execute. Review the token scope and secret exposure separately. Keep a record of who maintains it and when changes to its scripts or dependencies require another look. Organization-wide permission to restore one bot makes that reasoning harder to preserve.

Before the announced enforcement date, use policy insights to locate affected runs and assign an owner to each. Verify the actual schedule again before relying on it. If a temporary window produces a blocked run, retain the annotation as evidence of the policy effect; it does not by itself demonstrate a security defect in that workflow.

This is useful software maintenance work: connecting an automation's authority to its present purpose. Restore a workflow when that explanation holds, and keep its permissions narrow enough that the explanation remains true.