Development record
The external-review check runs the fork's own copy of itself on a pull_request_review event
The external-review check runs the fork's own copy of itself on a pull_request_review event
Published as security advisory GHSA-8rqx-7v43-wfpw; the advisory is the public account of this finding.
What
.github/workflows/external-review.yml:9-25 uses pull_request_target so that the required external-review check always runs the base repository's copy of itself; its header says a fork could otherwise "neuter the logic while keeping the required check's name green". The same workflow also triggers on pull_request_review, which GitHub runs from the pull request's merge ref, that is the fork's own copy of the file. A fork that edits the job to succeed, and then gets any account to leave a review, gets a green external-review context, which .abcd/work/rulesets/main-protection.json:37 requires.
GitHub documents pull_request_review with GITHUB_SHA as the pull request's merge commit (refs/pull/N/merge), the same as pull_request; only pull_request_target runs from the default branch. The job never checks that it is running the base copy, and main-protection.json requires the context by name with no integration_id. The two triggers share one concurrency group with cancel-in-progress: true, so a review-triggered run can also cancel the base-copy run.
Bounded by code ownership: any change under /.github/ needs a code-owner approval (.github/CODEOWNERS, require_code_owner_review: true in main-review.json). So the route weakens the two-reviewer rule to one owner approval of a visible workflow edit; it does not put unreviewed code on main. Not yet established: the same ruleset sets dismiss_stale_reviews_on_push: false and require_last_push_approval: false, so whether a code-owner approval given before a later workflow-editing push still counts needs a test on a throwaway fork. Found from code and GitHub's documentation; not run on GitHub.
Correction after triage
Removing the pull_request_review trigger would not close this. The required context is matched by name only, so a fork can equally add any new workflow on pull_request with a job named external-review. What bounds both routes is outside the workflow: the repository's fork-workflow approval policy, all_external_contributors (read on 2026-10-24), means no outside contributor's workflow runs until a maintainer approves it, and code-owner review covers /.github/. That policy is not recorded in the committed settings mirror, so a change to it would go unnoticed.
Revised fix: record the fork-workflow approval policy in the repository settings mirror (abcd ahoy remote, repo-settings.json) so drift is visible, and correct the workflow's header comment to name the controls it actually relies on. No change to how a consuming repository works.
Affected versions
The repository's CI configuration, not a released binary. Every revision with the pull_request_review trigger on that workflow.
Would it exist without abcd?
No. It is abcd's own required check and its own stated reason for pull_request_target. abcd added it, so abcd fixes it.
Fix
Drop the pull_request_review trigger and have a review event reach the check through a base-context route (for example pull_request_target on synchronize, or a re-run requested by a base-context workflow), or have the job refuse to report success when it is not running the base commit's copy of itself. No change to how a consuming repository works.
Frontmatter
| id | iss-2610280103488668 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | minor |
.abcd/work/issues/resolved/iss-2610280103488668-private-report.md
open on GitHub ↗ · commit history ↗