Privileged mode is not safe for untrusted jobs. GitLab's runner documentation says a privileged container has all the root capabilities of the host, so a job could gain full root access to the runner host, mount volumes and run nested containers. Use non-privileged containers, and isolate any runner that must be privileged.
What privileged mode changes
Containers normally get a limited set of Linux capabilities and a view of only their own processes. Privileged mode turns most of those restrictions off. GitLab's documentation says that enabling it effectively disables all the container's security mechanisms and exposes the host to privilege escalation, which can lead to container breakout.
It is also advised not to run job containers in the host PID namespace. GitLab calls that unsafe because it breaks isolation.
Why teams enable it anyway
The usual reason is building container images inside a CI job. A common setup runs a Docker daemon inside the job, and that needs elevated rights. People turn on privileged mode to make the build work and leave it on.
Safer options, in order
- Avoid needing it. Check whether your image builder can run without a daemon or without privileges, and prefer that.
- Run non-privileged, as non-root. GitLab says Docker can be considered safe in non-privileged mode, and suggests running jobs as a non-root user in containers with sudo disabled or SETUID and SETGID capabilities dropped. You can grant specific extra capabilities with cap_add and take some away with cap_drop.
- Keep the privileged runner separate. Put it in its own group, for a small set of trusted repositories, with no secrets on the host.
- Use one job per machine. For autoscaled setups, GitLab recommends MaxBuilds set to 1 with the Docker Machine executor, so a single virtual machine, which may be compromised, handles only one job.
- Do not mix trust levels. Never share a privileged runner between a public project and your private code.
Related settings people forget
| Setting | Risk | Safer choice |
|---|---|---|
| Shell executor | Jobs run with the runner user's permissions and can read code from other projects on the host | Use only for fully trusted builds |
| Pull policy if-not-present with private images | A later user may reuse a locally cached private image | Use the always policy |
| Host PID namespace | Breaks container isolation | Do not use |
The pull policy point comes from the same GitLab page, which explains that with if-not-present, one user's job can leave a private image on the runner that another user's job then uses without authentication.
How to check what you have today
- Look in your runner configuration for privileged settings, and note which runners use them.
- List which projects can use those runners.
- For each, ask whether the jobs really build images, and whether that could be done another way.
- Check the host for credentials, SSH keys and cloud metadata access. A privileged job can reach whatever the host can.
GitHub's hosted runners avoid some of these questions, because each job gets a fresh isolated virtual machine, according to GitHub's documentation. If your use of privileged mode is only to build images, moving that job to a hosted runner can remove the risk.
Scan the images you build
Whatever the runner mode, the image you produce can carry vulnerable packages. Scanning is a separate control from runner isolation.
Click through it at your own pace, or open it full screen.
Safeguard scans container images and dependencies, and policy gates can block a build that fails your rules. See also runner choices for small teams.
Quick check
Is rootless Docker the same as non-privileged mode?
No. They are different concepts. Non-privileged describes the container's capabilities, while rootless describes the daemon's user. Check each tool's documentation for what it guarantees.
Can I allow privileged mode for one trusted repository only?
Yes, by pinning that repository to a dedicated runner that no other project can use, and by keeping secrets off that host.
Sources
Last reviewed: 19 October 2026.