An open API service providing security vulnerability metadata for many open source software ecosystems.

GSA_kwCzR0hTQS14NHEzLWdjajMtbTZjZs4AB7fg

Critical CVSS: 9.9

gitea-runner: workflow container.options passes host namespaces and capability flags to job container when privileged mode is disabled

Affected Packages Affected Versions Fixed Versions
go:gitea.com/gitea/runner
PURL: pkg:go/gitea.com%2Fgitea%2Frunner
< 1.0.9-0.20260731160927-34bfa1915022 1.0.9-0.20260731160927-34bfa1915022
0 Dependent packages
0 Dependent repositories

Affected Version Ranges

All affected versions

v0.0.1, v0.1.0, v0.1.1, v0.1.2, v0.1.3, v0.1.4, v0.1.5, v0.1.6, v0.1.7, v0.1.8, v0.2.0, v0.2.1, v0.2.2, v0.2.3, v0.2.4, v0.2.5, v0.2.6, v0.2.7, v0.2.8, v0.2.9, v0.2.10, v0.2.11, v0.2.12, v0.2.13, v0.3.0, v0.3.1, v0.4.0, v0.4.1, v1.0.0, v1.0.1, v1.0.2, v1.0.3, v1.0.4, v1.0.5, v1.0.6, v1.0.7, v1.0.8

All unaffected versions

Summary

act_runner appends workflow-controlled jobs.<job>.container.options directly
to the Docker HostConfig for the job container. When runner privileged mode is
disabled, only Privileged is forced false. Host namespace flags, capability
expansion, and security profile overrides from workflow YAML are preserved in
the final HostConfig. A workflow author can enter host PID/IPC namespaces and
execute commands on the runner host as root.

Details

Source-to-sink path in act_runner:

  • ContainerSpec.Options accepts workflow YAML container.options
  • RunContext.options() appends workflow options to runner-level container options
  • Job container is created with Privileged: rc.Config.Privileged but also
    with Options: rc.options(ctx)
  • mergeContainerConfigs() parses Docker CLI-style options into HostConfig
  • When privileged mode is disabled, only copts.privileged is forced false
  • sanitizeConfig() only filters Binds and Mounts
  • Preserved dangerous HostConfig fields:
Privileged=false
PidMode=host
IpcMode=host
CapAdd=["ALL"]
SecurityOpt=["seccomp=unconfined","apparmor=unconfined"]

Attacker workflow YAML:

jobs:
  breakout:
    runs-on: ubuntu-latest
    container:
      image: ubuntu:22.04
      options: >-
        --pid=host --ipc=host --cap-add=ALL 
        --security-opt seccomp=unconfined 
        --security-opt apparmor=unconfined
    steps:
      - name: host namespace marker
        run: |
          nsenter -t 1 -m -u -i -n -p -- sh -c "id > /tmp/marker"

Impact

An attacker who can submit a workflow to a repository using a shared
Docker-backed act_runner can:

  • Enter host PID, IPC, and mount namespaces
  • Execute arbitrary commands as root on the runner host
  • Access runner host secrets, deployment credentials, and environment variables
  • Pivot to adjacent jobs running on the same runner
  • Access internal build infrastructure reachable from the runner host

Critical severity for shared runners where untrusted users can trigger
workflows. High severity for single-tenant runners with privileged mode
explicitly disabled as a security control.

Fix Direction

Treat container.options as untrusted input. Reject or strip when
privileged mode is disabled:

  • Host namespaces: --pid=host, --ipc=host, --uts=host, --network=host
  • Capability expansion: --cap-add ALL, --cap-add SYS_ADMIN
  • Security overrides: --security-opt seccomp=unconfined, --security-opt apparmor=unconfined
  • Device access: --device, --device-cgroup-rule
  • Volume inheritance: --volumes-from
  • Runtime controls: --runtime, --cgroup-parent
References: