Rules / GL043
GL043 Unanchored regex on user-controlled variable in rules condition
Severity: warn
OWASP: CICD-SEC-5 – Insufficient PBAC
Risk
GitLab CI rules:if uses =~ for regex matching. A regex without a trailing $ anchor is a prefix (or substring) match — an attacker who controls the matched variable can bypass the condition by crafting a value that satisfies the unanchored pattern.
For example, /^admin/ matches both admin and adminevil. If a job is gated on $GITLAB_USER_LOGIN =~ /^admin/, any user with a login starting with admin can trigger it.
What is flagged
rules:if conditions at job level and under workflow: that use =~ against one of the following user-controlled variables with an unanchored regex:
| Variable | Controlled by |
|---|---|
$GITLAB_USER_LOGIN |
The user triggering the pipeline |
$CI_COMMIT_BRANCH |
The pusher (branch name) |
$CI_COMMIT_REF_NAME |
The pusher (branch or tag name) |
$CI_PROJECT_NAMESPACE |
The project namespace |
Two cases are flagged:
- Prefix match — has
^but no trailing$:/^release/matchesrelease-evil - Unanchored — neither
^nor$:/admin/matches any value containingadmin
Trigger examples
deploy-prod:
rules:
- if: $CI_COMMIT_BRANCH =~ /^release/ # prefix match — "release-evil" also matches
script:
- ./deploy.sh
privileged-job:
rules:
- if: $GITLAB_USER_LOGIN =~ /^admin/ # prefix match — "adminevil" also matches
script:
- ./build.sh
restricted:
rules:
- if: $CI_PROJECT_NAMESPACE =~ /myteam/ # no anchors — any namespace containing "myteam" matches
script:
- ./build.sh
Safe alternative
Use both ^ and $ anchors to require an exact match:
deploy-prod:
rules:
- if: $CI_COMMIT_BRANCH =~ /^release$/
script:
- ./deploy.sh
privileged-job:
rules:
- if: $GITLAB_USER_LOGIN =~ /^deploy-bot$/
script:
- ./build.sh
restricted:
rules:
- if: $CI_PROJECT_NAMESPACE =~ /^myteam$/
script:
- ./build.sh
For patterns that intentionally match a family of values (e.g. all release/x.y branches), make the suffix explicit:
deploy-release:
rules:
- if: $CI_COMMIT_BRANCH =~ /^release\/\d+\.\d+$/
script:
- ./deploy.sh
Notes
- Only
=~is checked;==and!=comparisons are exact by definition and are not flagged - The check applies to both
workflow: rules:and per-jobrules: - Variables not in the list above (e.g.
$CI_PIPELINE_SOURCE) are not flagged — they are set by GitLab internally and are not attacker-controlled in the same way
Documentation for glsec 1.23.0. Source of this page · Rule implementation