Skip to content

preview check fails on every fork PR: pull_request_target + actions/checkout@v6 refuses fork checkout #211

Description

@carlosriosilva

Symptom

The preview check fails on every fork-originated pull request, regardless of what the PR changes. Contributors working from a fork never get a preview deployment, and their PR always shows a red check they cannot fix.

Same-repo branches are unaffected. Observed on the build-and-preview-site.yml run history: every recent dependabot branch and yi-nuo426-patch-1 pass; the only failures are the fork branch behind #107, which failed identically before and after an unrelated rebase.

Failing step log:

##[error]Refusing to check out fork pull request code from a 'pull_request_target' workflow.
This workflow runs with the base repository's GITHUB_TOKEN, secrets, default-branch cache
scope, and runner access. Fetching and executing a fork's code in that trusted context
commonly leads to "pwn request" vulnerabilities. To opt in, review the risks at
https://gh.io/securely-using-pull_request_target and set 'allow-unsafe-pr-checkout: true'
on the actions/checkout step.

Root cause

.github/workflows/build-and-preview-site.yml triggers on pull_request_target and then checks out the fork head with actions/checkout@v6:

https://github.com/meshery-extensions/shape-builder/blob/master/.github/workflows/build-and-preview-site.yml

on:
  pull_request_target:
    branches: [master]
...
      - name: Checkout PR
        uses: actions/checkout@v6
        with:
          repository: ${{ github.event.pull_request.head.repo.full_name }}
          ref: ${{ github.event.pull_request.head.sha }}
          persist-credentials: false

actions/checkout v6 added a hard refusal for this combination. It is not a misconfiguration that regressed - the action started rejecting a pattern the workflow was always using.

Please do not "fix" this with the one-line opt-in

Setting allow-unsafe-pr-checkout: true makes the check go green and introduces a real vulnerability. The job declares:

permissions:
  contents: write
  pull-requests: write

and then runs the fork's own build (npm ci / make, which execute fork-controlled lifecycle scripts) inside that trusted context. A malicious PR could read the write-capable GITHUB_TOKEN out of the runner environment and push to gh-pages or write to pull requests. That is precisely the pwn-request hazard the action's error text is warning about. The existing persist-credentials: false is good hygiene but does not remove the token from the job environment.

Suggested fix: split the workflow

Standard safe pattern for untrusted previews - never execute fork code in a privileged job:

  1. Build job on pull_request (untrusted, no secrets, permissions: contents: read): check out the fork head, build the site, upload the result with actions/upload-artifact. Fork code runs here, where there is nothing to steal.
  2. Deploy job on pull_request_target or workflow_run (privileged): download the artifact and publish/comment. It never checks out or executes fork code - it only moves already-built static files.

The closed-event cleanup path checks out gh-pages rather than fork code, so it can stay in the privileged job as-is.

Impact

Blocks preview deployments for all outside contributors, and trains reviewers to ignore a red check - which is how a genuine failure eventually gets waved through.

Found while taking over #107. Filed separately because it is repo-wide infrastructure and security-relevant, not a defect in that PR.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    help wantedExtra attention is neededkind/bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions