Safeguard
Security Guides•

Dedicated runners for privileged CI jobs: how to isolate them

If a CI job needs privileged containers, run it on dedicated, isolated, ephemeral machines limited to protected branches. Here is the setup in steps.

Safeguard Security Team
3 min read

If a job truly needs privileged mode, do not give that right to every runner. Run it only on dedicated runners that are isolated, ephemeral virtual machines, and restrict them to protected branches. That keeps the powerful setting away from untrusted pull requests and from jobs that do not need it.

What the guidance recommends

GitLab's runner security page addresses this case directly. It advises running containers with the privileged flag only on isolated and ephemeral virtual machines, configuring dedicated runners for jobs that need it, and having those runners execute jobs only on protected branches. It also suggests running user controlled scripts in their own network segment to reduce the impact of a malicious job.

Why privileged jobs deserve their own pool

A privileged container has far wider access to the host than a normal one. On a mixed pool, any pipeline that can reach that runner can use the power, including pipelines from less trusted contributors. Splitting the pool means a problem with one noisy or hostile pipeline cannot reach the machines that can do the most damage.

Setup in steps

  1. List the jobs that need it. Often it is only image builds that use a daemon. Check whether a daemonless builder or rootless mode removes the need. See Docker in Docker versus socket binding versus daemonless builds.
  2. Create a separate runner pool. Give it its own registration, tags and image, not shared with general builds.
  3. Use a fresh virtual machine per job. Full virtual machine isolation is stronger than containers on a shared host.
  4. Limit to protected refs. Configure the pool to run only jobs from protected branches and tags.
  5. Narrow credentials. The pool should hold only what image publishing needs, and use short-lived tokens where possible.
  6. Segment the network. Allow outbound access to the registry and package mirrors, and block lateral access to internal systems.
  7. Log everything. Ship runner and job logs externally, since the machine will be destroyed.

Table of what changes

SettingGeneral poolPrivileged pool
Who can run jobsAny project memberProtected branches only
Isolation unitContainerVirtual machine per job
CredentialsMinimalPublishing only
NetworkInternet through proxyRegistry and mirrors only
ReuseNeverNever

How to know it works

Open a test pull request from a branch that is not protected and confirm it cannot land on the privileged pool. Then try to reach an internal service from a job on that pool and confirm the network blocks it.

Quick check

Is a dedicated pool overkill for a small team?

If you have any privileged jobs, a second small pool is cheaper than the risk of making all runners privileged.

Can I run the privileged pool on the same cluster?

You can, but separate nodes and a separate namespace are the minimum. A separate account or network gives stronger isolation.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.