Skip to content

[sec-check] pr-verifier.yml pull_request_target with secrets:inherit + checks:write, no fork guard #6841

Description

@kubestellar-hive

Security Finding

Severity: medium
Type: unsafe-pattern (workflow / pwn-request surface)

.github/workflows/pr-verifier.yml runs on pull_request_target: [opened, edited, synchronize, reopened], passes secrets: inherit to the reusable workflow, and grants checks: write on the base-repo GITHUB_TOKEN — with no guard on github.event.pull_request.head.repo.fork and no restriction on which forked-PR revisions may reach the reusable workflow.

on:
  pull_request_target:
    types: [opened, edited, synchronize, reopened]

permissions:
  checks: write
  pull-requests: read

jobs:
  verify:
    uses: kubestellar/infra/.github/workflows/reusable-pr-verifier.yml@220beeeb8dae67e2fd8e89338ada8144609fc6ef  # main
    secrets: inherit

Two hardening gaps:

  1. secrets: inherit hands the entire org/repo secret set to the reusable workflow on every fork-PR event. Even though the reusable workflow is pinned by SHA (good), any future step that echoes an environment value, writes a debug artifact, or interpolates a secret into a run: block executed from PR-derived text becomes an exfil path — and fork PRs (including edited) provide untrusted input.
  2. No fork guard. pull_request_target runs with base-repo permissions on fork PRs by design. Combined with checks: write, the check-run text is attacker-controllable input territory unless the reusable workflow scrubs the PR title/body it consumes — same pwn-request class as homebrew-tap#378 and console-marketplace#619.

The pinned SHA 220beeeb… mitigates supply-chain risk on the reusable workflow itself; this finding is about the caller-side surface.

Impact

If the reusable workflow ever evaluates PR-derived text in a shell context (title/body → run:), an attacker opening a fork PR can:

  • forge or manipulate PR check-run status via checks: write on the base repo;
  • exfiltrate any inherited secret through log injection or an artifact upload.

Scope is the entire secret bundle available at the org/repo level, not just GITHUB_TOKEN.

Recommendation

Two concrete hardenings, in order of impact:

  1. Pass only the secrets the reusable workflow actually needs instead of secrets: inherit. If it only needs GITHUB_TOKEN, drop the line entirely (that token is provided automatically).
  2. Explicit fork guard on the caller job so the base-repo token never runs against untrusted revisions unless required:
    jobs:
      verify:
        if: github.event.pull_request.head.repo.full_name == github.repository
        uses: kubestellar/infra/.github/workflows/reusable-pr-verifier.yml@220beeeb…
    If pr-verifier must run on fork PRs (typical — it verifies title/body), then at minimum audit the reusable workflow (in kubestellar/infra) and confirm it never interpolates github.event.pull_request.title/body/head_ref into run: blocks unquoted, and never checks out the PR HEAD with credentials.

Also worth doing at the repo level: enable "Require approval for all outside collaborators" in Settings → Actions, which gates pull_request_target runs on fork PRs until a maintainer approves.

References


Filed by sec-check agent (ACMM L6 — full mode)

— hive: agent=sec-check backend=copilot model=claude-opus-4.7

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

    agent/securityApproved by a Hive merger/owner for auto-merge on green CIhelp wantedDenotes an issue that needs help from a contributor. Must meet "help wanted" guidelines.hive/hosted-kubestellar-console-4vktApproved by a Hive merger/owner for auto-merge on green CIsecurity

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions