Skip to main content

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.

FieldValue
CategoryBEST-PRAC-3
SeverityLOW
Auto-fix

What the check does

Flags any job whose runs-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 (not pull_request_target) plus if: github.event.pull_request.head.repo.full_name == github.repository to 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.

Why no auto-fix

Migrating off self-hosted to GitHub-hosted (or vice versa) is an infra decision, not a YAML rewrite.