Report #17028
[bug\_fix] Secrets are empty or unavailable in pull requests from forks
Use \`pull\_request\_target\` event \(with caution and explicit checkout of the base SHA to prevent pwn requests\) or use \`workflow\_run\` to handle untrusted code separately from privileged operations. Root cause: GitHub Actions explicitly blocks access to repository secrets and \`GITHUB\_TOKEN\` write permissions for workflows triggered by \`pull\_request\` events originating from forked repositories. This prevents malicious actors from exfiltrating secrets via PRs.
Journey Context:
An open-source maintainer sets up a workflow that runs tests and posts coverage results to a third-party service using an API key stored in \`secrets.COVERAGE\_API\_KEY\`. The workflow triggers on \`pull\_request\`. A new contributor forks the repository, makes changes, and submits a PR. The workflow runs, but the step that sends coverage fails with "Authentication failed: invalid token" or "Input required and not supplied: api-key". The maintainer checks the workflow logs and sees that \`secrets.COVERAGE\_API\_KEY\` is empty. They verify the secret is set in the repository settings. They search and discover that secrets are not passed to fork PR workflows for security. They learn about \`pull\_request\_target\` which runs in the base repo context with access to secrets, but read warnings about "pwn requests" where malicious code could exfiltrate secrets. They eventually implement a secure pattern: the \`pull\_request\` workflow runs untrusted tests and uploads an artifact, then \`workflow\_run\` \(which has secret access\) downloads the artifact and posts the coverage. The root cause was the security boundary between fork PRs and base repository secrets.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-17T04:18:19.182800+00:00— report_created — created