Rules / GL044
GL044 Untrusted MR source checkout in pipeline context
Severity: warn
OWASP: CICD-SEC-4 – Poisoned Pipeline Execution
CWE: CWE-829 – Inclusion of Functionality from Untrusted Control Sphere
Risk
GitLab CI pipelines triggered by merge requests run on the source branch — code controlled by the MR author. If a job in such a pipeline checks out $CI_MERGE_REQUEST_SOURCE_BRANCH_SHA and then executes code from that checkout, it runs attacker-controlled code with access to $CI_JOB_TOKEN and any protected variables available to the job.
This is a Poisoned Pipeline Execution (PPE) attack: the attacker opens an MR with malicious script content, which the pipeline then executes in a trusted context.
What is flagged
Jobs that combine:
- A trigger on merge request events (
rules:ifcontainingmerge_request_eventormerge_requests, or the legacyonly: [merge_requests]) - Any of:
script:orbefore_script:referencing$CI_MERGE_REQUEST_SOURCE_BRANCH_SHAimage:referencing$CI_MERGE_REQUEST_SOURCE_BRANCH_SHA(attacker-controlled container image)
Trigger example
security-scan:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- git checkout $CI_MERGE_REQUEST_SOURCE_BRANCH_SHA
- ./scan.sh # executes attacker-controlled code with $CI_JOB_TOKEN access
Safe alternatives
Run MR pipelines without access to protected variables:
Use inherit: variables: false combined with an explicit allowlist of non-sensitive variables, or run the job in a dedicated MR-only project with no protected variables.
Use GitLab's built-in MR diff analysis instead of checkout:
For code analysis, use GitLab's native SAST/code quality runners or CI components that analyse the MR diff without executing code from the source branch.
Only run trusted code in protected contexts:
Structure your pipeline so that jobs with access to $CI_JOB_TOKEN or protected variables only run on protected branches, never on MR source branches:
deploy:
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # protected branch only
script:
- ./deploy.sh
Notes
- This rule only flags
$CI_MERGE_REQUEST_SOURCE_BRANCH_SHA— the specific commit SHA of the MR source. The branch name variable (CI_MERGE_REQUEST_SOURCE_BRANCH_NAME) is not flagged as it is also commonly used for logging and artifact naming - The risk exists regardless of whether explicit secrets are referenced;
$CI_JOB_TOKENis always available and grants read access to the GitLab API on behalf of the pipeline
See also
Enable the ShellCheck integration to surface additional shell issues in these script blocks.
Documentation for glsec 1.23.0. Source of this page · Rule implementation