glsec

Rules / GL052

GL052 User-controlled variable in environment:name: grants protected environment access

Severity: warn
OWASP: CICD-SEC-6 – Insufficient Credential Hygiene
CWE: CWE-284 – Improper Access Control

Risk

GitLab's dynamic review environments use environment:name: with a variable to create per-branch environments — this is the recommended GitLab pattern. However, if the variable is user-controlled (branch name, MR title, commit message), an attacker can craft a value that resolves to the exact name of a protected environment and gain access to its secrets.

Protected environments in GitLab restrict who can deploy and which variables are exposed. Name matching is exact and string-based — there is no further verification that the job was triggered legitimately.

Example attack:

  1. Protected environment review/main exists with production-scoped secrets
  2. Attacker opens an MR from a branch named main
  3. Pipeline runs environment: name: review/$CI_COMMIT_REF_NAME → resolves to review/main
  4. Job receives the protected environment's variables

Trigger example

deploy-review:
  script:
    - ./deploy.sh
  environment:
    name: review/$CI_COMMIT_REF_NAME   # user-controlled — can be spoofed
deploy:
  script:
    - ./deploy.sh
  environment: deploy-$CI_COMMIT_BRANCH   # scalar shorthand, same risk

Safe alternatives

# Use a static environment name
deploy:
  script:
    - ./deploy.sh
  environment:
    name: production
# Use a prefix that cannot be a valid branch name, and restrict triggering branches
deploy-review:
  rules:
    - if: $CI_MERGE_REQUEST_IID
  script:
    - ./deploy.sh
  environment:
    name: review/mr-$CI_MERGE_REQUEST_IID   # MR IID is GitLab-assigned, not user-controlled

Notes

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