Insecure System Configuration
The systems that run the pipeline are themselves unpatched, over-permissioned or exposed.
If this is new to you
The machines that build and run your application are systems in their own right, and they usually receive far less hardening than the application does. Patching, least privilege, network restriction — all the discipline that goes into the production service somehow stops at the edge of the thing that builds it.
This matters more than it sounds, because the build host frequently has *more* access than the application it produces. It can reach your registry, your cloud account and your deployment target. The application can usually only reach a database.
What to do about it
Check what user your containers actually run as. An image with no `USER` instruction runs as root, and a great many published images still do. This is the cheapest check on this page and one of the most commonly failed.
Make the root filesystem read-only and mount a writable volume only where the application genuinely needs one. That removes a whole category of persistence: an attacker who cannot write a file cannot leave one behind.
Set `no-new-privileges` so a setuid binary inside the container cannot escalate, and drop all Linux capabilities, adding back only what actually breaks. For a typical web service, nothing breaks.
Going deeper
Never mount the Docker socket into a container you would not trust with root on the host, because that is precisely what you are granting. It is a common shortcut in CI containers and it collapses the boundary completely.
Beyond configuration, treat the CI system itself as a production service: patch it, keep it off the public internet, and give it the same monitoring you give anything else that holds credentials.
Words used on this pagedefinitions
- Linux capabilities
- Root's powers, split into individual permissions like binding low ports or changing file ownership. Containers get a default set most applications never use.
- no-new-privileges
- A flag preventing a process from gaining more privileges than its parent, which blocks setuid escalation inside a container.
- Read-only root filesystem
- Running a container whose own filesystem cannot be modified, so nothing an attacker writes survives.
- Docker socket
- The API endpoint that controls the Docker daemon. Access to it is equivalent to root on the host.
Why this matters
Pipelines are treated as infrastructure for the application and rarely as applications themselves, so the hardening that a production service receives — patching, least privilege, network restriction — often never reaches the machine that builds it. The build host frequently has more access than the thing it builds.
What it looks like in practice
If any of these sound familiar, that is the point — most of them are things somebody did for a sensible reason on a busy afternoon.
- A CI server reachable from the internet with an old version and a known advisory.
- Containers running as root because the image never set a user.
- A writable container filesystem, so an exploit can persist between requests.
- Docker socket mounted into a container, which is root on the host with extra steps.
- Default credentials on an internal tool that 'nobody outside can reach'.
Check your own pipeline
Questions you can actually answer, rather than a maturity score. If you cannot answer one of them, that is itself the finding — and a more useful one than a number.
What user does your container run as?
An image with no USER runs as root. This is the cheapest finding to check and one of the most common.
docker inspect --format '{{.Config.User}}' <image>Can the running container write to its own filesystem?
A read-only root filesystem with explicit tmpfs mounts removes a whole class of persistence.
Which capabilities does the container actually hold?
Containers keep a default capability set that most applications never use. Dropping all and adding back is the safer direction.
docker inspect --format '{{.HostConfig.CapDrop}}' <container>
How to fix it
- Run as a non-root user, declared in the image so it cannot be forgotten at runtime.
- Make the root filesystem read-only and mount tmpfs for the paths that genuinely need writes.
- Set `no-new-privileges` so a setuid binary cannot escalate.
- Drop all capabilities and add back only what breaks, which is usually nothing.
- Never mount the Docker socket into a container you would not trust with root on the host.
Did this get you to an answer?
No text box on purpose — please do not paste production logs anywhere
Risk taxonomy from OWASP Top 10 CI/CD Security Risks (Daniel Krivelevich and Omer Gil, September 2022, CC BY-SA 4.0). Explanations, checks, fixes and definitions written for this site.