Documentation Index
Fetch the complete documentation index at: https://docs.pipefort.com/llms.txt
Use this file to discover all available pages before exploring further.
| Field | Value |
|---|---|
| Category | BEST-PRAC-3 |
| Severity | LOW |
| Auto-fix | ✗ |
What the check does
Flags any job whoseruns-on: includes the label self-hosted — either as a scalar (runs-on: self-hosted) or as one element of a sequence (runs-on: [self-hosted, linux, x64]).
Why it matters
Self-hosted runners execute workflow code on infrastructure you control. That’s fine for private repos with trusted contributors. It’s dangerous for repos that accept pull requests from forks — by default, a PR triggers workflows on the runner, so an attacker can submit a PR whose CI does anything the runner can reach: scan your VPC, exfiltrate keys mounted on the host, install persistence.Severity
This is flagged as LOW because self-hosted runners are often an intentional infrastructure choice (compliance, hardware needs, private network access). The check is a reminder to double-check the surrounding controls — not a blanket “don’t do this.”Mitigations
If you keep self-hosted runners:- Use ephemeral runners that destroy themselves after each job — prevents persistence and cross-job contamination.
- Don’t run them on public-PR repos. Either restrict the runner to private repos, or gate PR triggers on
pull_request(notpull_request_target) plusif: github.event.pull_request.head.repo.full_name == github.repositoryto skip forks. - Network-isolate the runner. Block egress to anything it doesn’t strictly need; deny outbound to your VPC.
- Don’t mount host credentials. No AWS instance profiles, no GCP service accounts on the runner machine itself — fetch them per-job via OIDC.
- Run in containers. Each job gets a fresh container; no shared state.