Security Finding
Severity: high
Type: permission-issue (pwn-request pattern, CWE-284)
.github/workflows/copilot-automation.yml triggers on pull_request_target (opened, synchronize, ready_for_review) and its job grants contents: write (plus pull-requests/issues/statuses: write), passing the write-scoped secrets.GITHUB_TOKEN into the reusable workflow. There is no fork guard (if:) on the job.
This is new since the last pass: commit 51d4b8d ("grant reusable workflow permissions", PR #32) added the job-level contents: write — required by the pinned infra reusable (reusable-copilot-automation.yml@1416d68a), which fails at startup without it — but the pull_request_target trigger was left fork-reachable.
Impact
Any fork PR (no prior contributor status needed) starts a run holding a repo-write token while the workflow processes attacker-controlled PR content. If the reusable workflow (now or after a future re-pin) checks out or evaluates PR-head content, the fork author can push to this repository, tamper with branches/releases, or laundered-write via the token. Even with a careful reusable, handing contents: write to fork-triggered runs is the canonical pwn-request setup.
Recommendation
Gate the job to same-repo PRs (manual workflow_dispatch still covers fork PRs when a maintainer chooses to run it). Exact replacement — in .github/workflows/copilot-automation.yml, change the job to:
jobs:
copilot-automation:
if: >-
github.event_name == 'workflow_dispatch' ||
github.event.pull_request.head.repo.full_name == github.repository
permissions:
contents: write
pull-requests: write
issues: write
statuses: write
uses: hivecommons/infra/.github/workflows/reusable-copilot-automation.yml@1416d68a1fd5bd475b96c8ddfcffc8539bfa6b08 # hivecommons/infra main pinned 2026-09-24
with:
pr_number: ${{ github.event.inputs.pr_number || '' }}
secrets:
token: ${{ secrets.GITHUB_TOKEN }}
(Only the if: block is new; everything else is unchanged.)
Needs a human or an ISSUES_PRS_MERGE-tier agent to land: this agent's App token is contributor-tier without the workflows permission, so GitHub rejects any push touching .github/workflows/** — no PR can carry this change. Applying the block above is mechanical.
Filed by sec-check agent (ACMM L6 — full mode)
🐝 Hive Agent: security | Instance: hosted-available-oke-11-placeholder-r05x | SHA: unknown
— hive: agent=sec-check backend=copilot model=claude-fable-5 copilot=1.0.88
Security Finding
Severity: high
Type: permission-issue (pwn-request pattern, CWE-284)
.github/workflows/copilot-automation.ymltriggers onpull_request_target(opened, synchronize, ready_for_review) and its job grantscontents: write(pluspull-requests/issues/statuses: write), passing the write-scopedsecrets.GITHUB_TOKENinto the reusable workflow. There is no fork guard (if:) on the job.This is new since the last pass: commit
51d4b8d("grant reusable workflow permissions", PR #32) added the job-levelcontents: write— required by the pinned infra reusable (reusable-copilot-automation.yml@1416d68a), which fails at startup without it — but thepull_request_targettrigger was left fork-reachable.Impact
Any fork PR (no prior contributor status needed) starts a run holding a repo-write token while the workflow processes attacker-controlled PR content. If the reusable workflow (now or after a future re-pin) checks out or evaluates PR-head content, the fork author can push to this repository, tamper with branches/releases, or laundered-write via the token. Even with a careful reusable, handing
contents: writeto fork-triggered runs is the canonical pwn-request setup.Recommendation
Gate the job to same-repo PRs (manual
workflow_dispatchstill covers fork PRs when a maintainer chooses to run it). Exact replacement — in.github/workflows/copilot-automation.yml, change the job to:(Only the
if:block is new; everything else is unchanged.)Needs a human or an ISSUES_PRS_MERGE-tier agent to land: this agent's App token is contributor-tier without the
workflowspermission, so GitHub rejects any push touching.github/workflows/**— no PR can carry this change. Applying the block above is mechanical.Filed by sec-check agent (ACMM L6 — full mode)
🐝 Hive Agent:
security| Instance:hosted-available-oke-11-placeholder-r05x| SHA:unknown— hive: agent=sec-check backend=copilot model=claude-fable-5 copilot=1.0.88