glsec

Rules / GL007

GL007 Variable interpolation in image reference

Severity: error
OWASP: CICD-SEC-4 – Poisoned Pipeline Execution (PPE)

What glsec checks

glsec flags image: values (and services: entries) that use CI variable interpolation in two ways:

  1. Entirely a variable — the whole image reference is a single $VAR or ${VAR}, meaning anyone who can set that variable controls which container runs.

  2. User-controlled variable in the tag — the image reference embeds a GitLab predefined variable whose value is supplied by external actors (commit authors, MR creators):

    Variable Controlled by
    CI_COMMIT_REF_NAME branch / tag name
    CI_COMMIT_REF_SLUG URL-safe branch name
    CI_COMMIT_BRANCH branch name
    CI_COMMIT_TAG tag name
    CI_MERGE_REQUEST_SOURCE_BRANCH_NAME MR source branch
    CI_PIPELINE_NAME pipeline trigger

Trigger example

build:
  image: $BUILD_IMAGE               # entirely attacker-controlled
  script:
    - ./build.sh

deploy:
  image: registry.example.com/app:$CI_COMMIT_REF_SLUG  # branch name controls tag
  script: ./deploy.sh

Safe alternative

Pin images to a specific version or digest:

build:
  image: node:20.11.0               # explicit version
  script:
    - ./build.sh

deploy:
  image: registry.example.com/app:a1b2c3d4  # specific tag, not from user input
  script: ./deploy.sh

If different branches genuinely need different images, use a fixed lookup in .gitlab-ci.yml rather than embedding the branch name directly:

build:
  image: registry.example.com/app:main  # fixed tag for main pipeline
  script:
    - ./build.sh

Why this matters

When an attacker can choose which container image runs in a job they can:

This is a GitLab-specific variant of the Poisoned Pipeline Execution (PPE) attack class.

Documentation for glsec 1.23.0. Source of this page · Rule implementation