Rules / GL013
GL013 Production deploy job without branch restriction
Severity: warn
OWASP: CICD-SEC-1 – Insufficient Flow Control Mechanisms
What glsec checks
glsec flags jobs that deploy to a production-like environment but have no rules: or only: clause to restrict which branches or conditions can trigger the deployment.
A job is considered production-like if either:
- its
environment:name contains (case-insensitive)production,prod,live, orstaging; or - its
environment:deployment_tierisproductionorstaging— this catches jobs whose name is an arbitrary string (e.g.my-app,eu-west) but which declare themselves a prod/staging target via the structured field.
Both the scalar form and the {name: ..., url: ...} mapping form are checked.
Trigger example
deploy-prod:
stage: deploy
environment: production # no rules: — any branch can deploy
script: ./deploy-to-prod.sh
deploy-eu:
stage: deploy
environment:
name: eu-west # name not a prod keyword …
deployment_tier: production # … but the tier declares it production
script: ./deploy-to-prod.sh
Safe alternative
Restrict the job to the default protected branch:
deploy-prod:
stage: deploy
environment: production
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_REF_PROTECTED == "true"'
script: ./deploy-to-prod.sh
Or with the legacy only: syntax:
deploy-prod:
stage: deploy
environment: production
only:
- main
script: ./deploy-to-prod.sh
Why this matters
Without a branch restriction:
- Any developer with pipeline trigger access can deploy to production from any branch
- Hotfix or feature branches can accidentally deploy untested code
- Manual pipeline runs from the GitLab UI can bypass normal review workflows
- GitLab's environment protection rules (defined in Settings → CI/CD → Environments) are a second line of defence, not a substitute for restricting which pipelines can target the environment
Documentation for glsec 1.23.0. Source of this page · Rule implementation