# CI runner privileged session injection

Workflow-controlled options or shared sessions let a job reach the privileged provisioner or host

_Area: Software supply chain and CI/CD. Seen in 3 disclosed reports; 2 confirmed bounties: $500 and $10,000; latest 2026-10-02. Updated 2026-11-02._

## How it works
A CI job is supposed to be a sandbox: untrusted workflow code runs with limited power, while a privileged component (a provisioner agent, the runner host, a monitoring daemon) holds the real authority. The assumption that breaks is that the boundary between the two is enforced. In practice the job and the privileged component often share a session, a user account, or a container config, so the job can reach across and act with the privileged component's rights. The isolation is assumed, not built.

## Where it shows up
- A privileged agent (provisioner, scanner, monitor) running as the same OS user and in the same session as job scripts [E2](https://bugbountylibrary.com/r/blog%3Agithub-com-stackoverflowexcept1on-how-to-hack-github-actions.md).
- Workflow YAML fields that flow into container creation options (`container.options`) and are merged into the host config [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-x4q3-gcj3-m6cf.md).
- Sanitizers that only strip some dangerous fields (e.g. Binds/Mounts) while leaving `PidMode`, `IpcMode`, `CapAdd`, `SecurityOpt`, `Devices`, `VolumesFrom` [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-x4q3-gcj3-m6cf.md).
- "Privileged" gating that only forces the `Privileged` boolean false and trusts everything else [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-x4q3-gcj3-m6cf.md).
- Workflows that let PR authors modify CI YAML or run `run:` steps on self-hosted runners [E1](https://bugbountylibrary.com/r/blog%3Amarcyoung-us-post-zuckerpunch.md).
- .NET agents on hosted runners that can be opened and patched from a sibling process [E2](https://bugbountylibrary.com/r/blog%3Agithub-com-stackoverflowexcept1on-how-to-hack-github-actions.md).

## How to review
Find every privileged component that shares a session, user, or container config with job-controlled code. The invariant: no workflow-controlled input may reach a field or process that grants host-level power, and the privileged component must run in a separate session/user the job cannot touch. Trace `container.options` (or equivalent) end to end into the final host config and list every field that survives sanitization; each surviving field that grants host namespaces or capabilities is a finding. For agents, check whether the job user can OpenProcess/WriteProcessMemory into them. For workflows, check whether an unprivileged contributor can change the YAML that runs on a self-hosted runner.

## How finders spotted it
- Read a blog on crypto-mining via PRs, asked how GitHub detects it, pulled `provisioner.exe` out via workflow artifacts, reverse-engineered it in dnSpyEx, and saw it ran unisolated as runneradmin [E2](https://bugbountylibrary.com/r/blog%3Agithub-com-stackoverflowexcept1on-how-to-hack-github-actions.md).
- Source review of the runner container path: traced options through merge and sanitize functions and noticed only Binds/Mounts were filtered [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-x4q3-gcj3-m6cf.md).
- Knew the dangerous workflow-modification checkbox and mass-tested candidate repos via PRs, hiding diffs with a force-push rebase trick [E1](https://bugbountylibrary.com/r/blog%3Amarcyoung-us-post-zuckerpunch.md).

## Variants seen
- Process injection into a same-session privileged .NET agent, with detection hooks disabled [E2](https://bugbountylibrary.com/r/blog%3Agithub-com-stackoverflowexcept1on-how-to-hack-github-actions.md).
- Container option injection granting host PID namespace and all capabilities [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-x4q3-gcj3-m6cf.md).
- Workflow YAML modification on self-hosted runners leading to root, then cloud IAM/ECR pivot [E1](https://bugbountylibrary.com/r/blog%3Amarcyoung-us-post-zuckerpunch.md).

## Impact and severity
Reached root on the runner host [E1](https://bugbountylibrary.com/r/blog%3Amarcyoung-us-post-zuckerpunch.md)[E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-x4q3-gcj3-m6cf.md), full evasion of the provisioner's security system [E2](https://bugbountylibrary.com/r/blog%3Agithub-com-stackoverflowexcept1on-how-to-hack-github-actions.md), and pivots to IAM, ECR image repush, deployment credentials and adjacent jobs [E1](https://bugbountylibrary.com/r/blog%3Amarcyoung-us-post-zuckerpunch.md)[E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-x4q3-gcj3-m6cf.md). Severity is raised by cloud overprovisioning and downstream supply-chain reach.

## Why fixes fail
Forcing only the `Privileged` flag and stripping Binds/Mounts leaves equivalent-power fields intact [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-x4q3-gcj3-m6cf.md).

## Seen in real software
Open-source packages and projects, and products, where this pattern was found. If the target runs one, compare the version it runs with the fix.
- **gitea.com/gitea/runner (go)** < 1.0.9-0.20260731160927-34bfa1915022, fixed in 1.0.9-0.20260731160927-34bfa1915022: gitea-runner: workflow container.options passes host namespaces and capability flags to job container when privileged mo (CVE-2026-73802). Report: https://bugbountylibrary.com/r/ghsa%3AGHSA-x4q3-gcj3-m6cf.md
- **Virtual Environment Provisioner** (provisioner.exe) (version not stated): How to hack Github Actions. Report: https://bugbountylibrary.com/r/blog%3Agithub-com-stackoverflowexcept1on-how-to-hack-github-actions.md

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Amarcyoung-us-post-zuckerpunch.md
- E2: https://bugbountylibrary.com/r/blog%3Agithub-com-stackoverflowexcept1on-how-to-hack-github-actions.md
- E3: https://bugbountylibrary.com/r/ghsa%3AGHSA-x4q3-gcj3-m6cf.md
