Security: drift.yml pull_request trigger + host-docker-socket smoke job is a pwn-request vector #266

Closed
opened 2026-07-19 03:33:05 +00:00 by hexajon · 0 comments
hexajon commented 2026-07-19 03:33:05 +00:00 (Migrated from codeberg.org)

Once the repo is public and takes fork PRs, drift.yml has a classic pwn-request shape that needs closing (or a runner-config confirmation) before launch.

The chain:

  • .forgejo/workflows/drift.yml:35-36 triggers on pull_request.
  • The forgejo-smoke job is gated by if: ${{ vars.RUN_FORGEJO_SMOKE == 'true' }} (line 99) and runs docker ps/docker exec against the HOST docker socket to provision the sidecar admin (around line 167).
  • It then executes PR-modifiable content: the job's own run: blocks and tests/integration/forgejo-smoke.sh (invoked ~line 183).

On Codeberg the var is unset, so the job is skipped - safe there. The exposure is on the org runner, where RUN_FORGEJO_SMOKE=true and the docker socket is reachable: a hostile fork PR that edits drift.yml or forgejo-smoke.sh gets code execution with host-docker-socket access, which is host root. The provisioned admin token itself is confined to the ephemeral throwaway Forgejo sidecar and can't reach outside the job - the risk is the socket, not the token.

This is blocked if and only if the runner does NOT auto-run untrusted fork-PR workflows (manual approval required). That policy lives in runner config, not repo source, so it can't be confirmed from here.

Fix (either):

  1. Confirm the org runner requires manual approval for fork-PR workflow runs (and document it), OR
  2. Drop pull_request from the socket-privileged smoke job - restrict it to push / schedule / workflow_dispatch so PR-controlled code never runs in the socket-privileged context.

Option 2 is the durable fix and doesn't depend on runner policy staying correct. This is the single most important pre-public item from the security sweep.

Once the repo is public and takes fork PRs, `drift.yml` has a classic pwn-request shape that needs closing (or a runner-config confirmation) before launch. The chain: - `.forgejo/workflows/drift.yml:35-36` triggers on `pull_request`. - The `forgejo-smoke` job is gated by `if: ${{ vars.RUN_FORGEJO_SMOKE == 'true' }}` (line 99) and runs `docker ps`/`docker exec` against the HOST docker socket to provision the sidecar admin (around line 167). - It then executes PR-modifiable content: the job's own `run:` blocks and `tests/integration/forgejo-smoke.sh` (invoked ~line 183). On Codeberg the var is unset, so the job is skipped - safe there. The exposure is on the org runner, where `RUN_FORGEJO_SMOKE=true` and the docker socket is reachable: a hostile fork PR that edits `drift.yml` or `forgejo-smoke.sh` gets code execution with host-docker-socket access, which is host root. The provisioned admin token itself is confined to the ephemeral throwaway Forgejo sidecar and can't reach outside the job - the risk is the socket, not the token. This is blocked if and only if the runner does NOT auto-run untrusted fork-PR workflows (manual approval required). That policy lives in runner config, not repo source, so it can't be confirmed from here. Fix (either): 1. Confirm the org runner requires manual approval for fork-PR workflow runs (and document it), OR 2. Drop `pull_request` from the socket-privileged smoke job - restrict it to `push` / `schedule` / `workflow_dispatch` so PR-controlled code never runs in the socket-privileged context. Option 2 is the durable fix and doesn't depend on runner policy staying correct. This is the single most important pre-public item from the security sweep.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sixfold-space/madtea#266
No description provided.