Skip to main content
ISSUE-412 High Medium Pipeline Composition

Docker-in-Docker service detected

Control: Pipeline must not use Docker-in-Docker · Config key: pipelineMustNotUseDockerInDocker

📋 What is this?

A CI/CD job uses a Docker-in-Docker (dind) service. On shared runners running in privileged mode, this creates a Docker daemon inside the CI container that enables container escape, lateral movement between jobs, and access to secrets from other projects on the same runner.

⚠️ Impact

Docker-in-Docker in privileged mode grants near-root access to the host. An attacker (or a compromised dependency) can escape the container, list and inspect other containers on the runner, read volumes mounted by other CI jobs (potentially containing secrets), and probe the runner's internal network.

🔧 How to fix

Replace Docker-in-Docker with a rootless container build tool. Kaniko builds container images inside a container without requiring a Docker daemon or privileged mode.

✗ Before This job runs a Docker daemon inside the CI container, requiring privileged mode on the runner.
# .gitlab-ci.yml — ❌ Uses Docker-in-Docker service
build-image:
image: docker:27
services:
- docker:27-dind
variables:
DOCKER_HOST: tcp://docker:2376
DOCKER_TLS_CERTDIR: "/certs"
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
✓ After Kaniko builds container images without requiring a Docker daemon or privileged mode.
# .gitlab-ci.yml — ✅ Uses Kaniko (no privileged mode needed)
build-image:
image:
name: gcr.io/kaniko-project/executor:v1.23.2-debug
entrypoint: [""]
script:
- /kaniko/executor
--context $CI_PROJECT_DIR
--dockerfile $CI_PROJECT_DIR/Dockerfile
--destination $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
# .plumber.yaml
# pipelineMustNotUseDockerInDocker:
# enabled: true
# detectInsecureDaemon: true

💡 Tips

  • Kaniko and Buildah are the most common alternatives to Docker-in-Docker for building container images in CI/CD.
  • If Docker-in-Docker is truly required, ensure it runs on dedicated (not shared) runners with proper network isolation.
  • The detectInsecureDaemon option (default: true) also flags jobs where TLS is disabled between the CI job and the DinD daemon.
  • This control inspects the services: declaration in the CI configuration. A Docker daemon started manually from script: (e.g., dockerd &) or embedded in a custom image is not detected (known limitation).
  • Only images with docker: prefix and a tag containing dind or latest are matched. Renamed or aliased DinD images (e.g., myregistry.com/custom-builder:stable) are not detected.

⚙️ Configuration

This control is configured in .plumber.yaml under the key:

controls:
  pipelineMustNotUseDockerInDocker:
    enabled: true

See the CLI documentation for the full configuration reference.