Skip to content

ci: keep fork PR builds off the self-hosted runner - #9

Merged
draxios merged 2 commits into
mainfrom
security/ci-fork-prs-off-self-hosted
Nov 3, 2026
Merged

draxios merged 2 commits into
mainfrom
security/ci-fork-prs-off-self-hosted

Conversation

@draxios

@draxios draxios commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Security fix (primary)

.github/workflows/ci.yml triggers on pull_request and the test job ran on [self-hosted, linux] with no fork guard — it checks out the PR and runs ensure-prereqs.sh, pip install, and tests/run.sh, executing fork-supplied code on our persistent, shared self-hosted runner. A malicious fork PR = remote code execution + secret/credential exfiltration on the runner, with a foothold that outlives the job and can reach other repos (the runner is in the org Default group, visible to all repos). The only gate today is the maintainer 'Approve and run' click, which is not a real boundary.

Fix: route all PR builds to an ephemeral GitHub-hosted runner; keep self-hosted for trusted push/workflow_dispatch only (same pattern as morass):

runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || fromJSON('["self-hosted", "linux"]') }}

Build-reliability fix (required to make the above green)

Routing PR CI to a clean runner surfaced a latent bug: tests/run.sh hardcoded SourceMod snapshot git7210, which AlliedMods has since pruned (404). curl -s (no --fail) saved the HTML error page and tar failed with not in gzip format. The self-hosted runner only passed because it had the toolchain cached — this would have broken it too once its cache cleared.

Fix: resolve the current build from the sourcemod-latest-<os> pointer and use curl -f so a bad download aborts clearly.

Verification

First PR run correctly executed on ubuntu-latest (not self-hosted) — confirms the routing. Re-running with the toolchain fix now.

pull_request builds check out and execute untrusted fork code
(ensure-prereqs.sh, pip install, tests/run.sh). Running that on the
persistent self-hosted runner is a remote code execution and secret
exfiltration vector gated only by a maintainer's approval click.

Route all PR builds to an ephemeral GitHub-hosted runner (free for
public repos); keep the self-hosted runner for trusted push/dispatch
events only. CI still runs for fork PRs, just never on self-hosted.
The hardcoded git7210 snapshot has been pruned from the AlliedMods drop
server (404), so a clean runner downloaded the HTML error page and tar
failed with 'not in gzip format'. The self-hosted runner only passed
because it had the toolchain cached.

Resolve the current build from the sourcemod-latest-<os> pointer and use
curl -f so an HTTP error aborts with a clear message instead of writing
a junk archive.
@draxios
draxios merged commit a9eb344 into main Nov 3, 2026
1 check passed
@draxios
draxios deleted the security/ci-fork-prs-off-self-hosted branch November 3, 2026 23:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant