Skip to content

[FEAT] New control: pipelineMustNotUseDockerInDocker — detect dind services #84

@stephrobert

Description

@stephrobert

Is your feature request related to a problem? Please describe.

When a CI job uses services: [docker:dind] (Docker-in-Docker), it creates a Docker daemon inside the CI container. On shared runners running in privileged mode, this enables:

  • Container escape: Access to the host's Docker daemon and kernel namespaces
  • Lateral movement: Listing/inspecting containers from other projects running on the same runner
  • Volume access: Reading volumes mounted by other CI jobs (potentially containing secrets)
  • Network reconnaissance: Probing the runner's internal network

This is a well-known attack vector documented in GitLab CI security best practices.

Describe the solution you'd like

Add a new control pipelineMustNotUseDockerInDocker that:

  • Detects docker:dind (and variants like docker:*-dind, docker:latest) in services: blocks
  • Optionally detects insecure configurations: DOCKER_TLS_CERTDIR: "" or DOCKER_HOST: tcp://docker:2375 (unencrypted)
  • Reports each affected job with a warning

Configuration in .plumber.yaml

controls:
  pipelineMustNotUseDockerInDocker:
    enabled: true
    # Suggest alternatives in the output
    suggestAlternatives: true  # e.g., kaniko, buildah
    # Also flag insecure Docker daemon configuration
    detectInsecureDaemon: true  # DOCKER_TLS_CERTDIR="" or tcp://docker:2375

Implementation Hints

These are just ideas. Feel free to change the implementation.

  1. Data source: The PipelineImage collector already parses images from CI jobs, including services:. The PipelineOrigin collector provides the merged CI config with per-job variables.
  2. New control file: Create control/controlGitlabPipelineDockerInDocker.go.
  3. Logic:
    • Iterate over all jobs from the merged CI config
    • For each job, check services: for images matching docker:dind or docker:*-dind
    • Optionally check job variables for DOCKER_TLS_CERTDIR: "" or DOCKER_HOST pointing to tcp://...:2375 (non-TLS)
  4. Compliance: 0% if any job uses docker:dind, 100% otherwise.
  5. Output: Include the job name, the dind image reference, and (if suggestAlternatives is enabled) a recommendation to use kaniko or buildah instead.

Files Touched

  • control/controlGitlabPipelineDockerInDocker.go (new control)
  • control/types.go (add result field to AnalysisResult)
  • control/task.go (wire the new control in RunAnalysis())
  • configuration/plumberconfig.go (add config struct and getter)
  • .plumber.yaml (add default config section)
  • cmd/analyze.go (add output formatting)

Why It's Valuable

Docker-in-Docker is one of the most common and dangerous patterns in CI/CD pipelines, especially on shared runners. While it's sometimes necessary, teams should be aware of the risk and consider alternatives like kaniko or buildah. This control raises visibility on the attack surface without necessarily blocking the build — compliance teams can decide whether to enforce or just warn.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions