Self-Hosted Runner Security

Security Considerations for Self-Hosted Runners on Public Repositories

GitHub 29 's guidance is blunt: self-hosted runners "should almost never be used for public repositories". Anyone can open a pull request from a fork whose workflow, or whose npm 2,036 test, runs code of their choosing. On a GitHub-hosted runner that code dies with the virtual machine; on yours it runs on hardware that persists, inside your network, perhaps next to cloud credentials, SSH keys or a Docker 514 socket.

How a fork pull request reaches a self-hosted runner, and where each defense sits
How a fork pull request reaches a self-hosted runner, and where each defense sits

BookNest's repository is public, so the demo shrank every link of that chain: a container instead of the host, a label no other workflow uses, a workflow that only workflow_dispatch (which needs write access) can start, one job only, and removal right after it. The approval rule for fork pull requests was also tightened from GitHub's default (first-time contributors) to every outside contributor:

Requiring approval for every outside contributor's workflow runsShell
gh api -X PUT repos/{owner}/{repo}/actions/permissions/fork-pr-contributor-approval \
  -f approval_policy=all_external_contributors
gh api repos/{owner}/{repo}/actions/permissions/fork-pr-contributor-approval
Output
{"approval_policy":"all_external_contributors"}

Approval is only a speed bump: approving without reading the diff still runs the attacker's code. And GitHub warns there is "no way to guarantee that a self-hosted runner only runs one job", hence a container deleted with it.

For real use, give self-hosted runners to private repositories, run each job on a fresh virtual machine or container (GitHub's Actions Runner Controller (https://github.com/actions/actions-runner-controller 6,531 ) does this on Kubernetes 5,150 , which Kubernetes introduces), keep secrets out of their environment, and never let a pull_request_target workflow check out and run a fork's code on them.