For private repositories, two settings can let workflows from fork pull requests use a write token or all of your secrets. Leave both off unless you fully trust everyone who can fork. A fork pull request carries code you did not write, and these settings give that code your access.
Where the settings live
GitHub's repository Actions settings have a separate section for fork pull request workflows that is available only for private repositories. Two options in it matter here, with these descriptions from the documentation:
- Send write tokens to workflows from pull requests: allows pull requests from forks to use a GITHUB_TOKEN with write permission.
- Send secrets to workflows from pull requests: makes all secrets available to the pull request.
For public repositories the control is different. There, a setting named for approval of fork pull request workflows decides whether a maintainer must approve a run first.
Why these are sharp tools
A pull request from a fork runs the workflow file from the pull request when the trigger is the plain pull request trigger. That means the contributor can change the commands the runner executes. With these two options off, a hostile change has little to take, which is why they are off unless someone enables them. Confirm the current behavior in GitHub's documentation for your plan.
Turn on write tokens and the run can change repository contents, packages or pull requests. Turn on secrets and the run can read every secret available to the workflow, then send it anywhere the runner can reach. GitHub's guidance says any user with write access can read your secrets, and these settings extend that reach to whoever can open a fork pull request in a private repository.
When someone enables them
Usually for convenience: a private repository with a small trusted team, a test that needs a credential, or a bot that comments on fork pull requests. The reasons are understandable, and the risk grows with the number of people who can fork. In an organization, that can be more people than the team thinks, depending on who has access.
Safer patterns
| Need | Safer approach |
|---|---|
| Run tests on fork pull requests | Use the default read only token and no secrets, and write tests that do not need credentials |
| Post a comment or label on a fork pull request | Split into two workflows: an unprivileged one builds and uploads results, a privileged one reads the results and comments, without running fork code |
| Need a credential for integration tests | Run those tests after merge, or on branches pushed by members, with environment secrets behind approval |
| Many outside contributors | Require approval before runs from contributors, as the fork approval settings allow |
The two workflow pattern is described in scan fork pull requests without secrets, the two workflow pattern and workflow_run for separating privileged workflows. Be careful with the privileged half: GitHub advises against using the pull request target and workflow run triggers with untrusted code or content, so the privileged workflow must never check out or run the fork's code.
An audit step
For each private repository that accepts fork pull requests, open the Actions settings and read the fork section. Note which options are on. Where either is on, write down the reason and who accepted the risk, then try to remove the need.
Quick check
Are these settings on by default?
GitHub describes them as options you enable. The safe state is both off, and you should check each repository, since settings can be changed per repository.
Does approving a first-time contributor's run make it safe?
Approval lets you read the change before it runs, which helps. It is not a substitute for keeping secrets out of reach of fork code.
Sources
Last reviewed: 19 October 2026.