CVE-2022-2251 - How Improper Branch Name Sanitization Led to Command Injection in GitLab Runner
If you use GitLab CI/CD pipelines regularly, knowing about CVE-2022-2251 is crucial. This vulnerability, disclosed in 2022, affected almost every version of GitLab Runner before 15.3.5, 15.4.4, and 15.5.2. It allowed attackers to run arbitrary commands on the build host—just by creating a branch with a sneaky name. In this post, I'll break down how this worked, why it happened, and how you can protect yourself.
What is CVE-2022-2251?
CVE-2022-2251 is a critical vulnerability in GitLab Runner, the agent that executes your pipeline jobs. The flaw is in the way branch names are sanitized when used in certain pipeline jobs. It lets attackers craft branch names containing shell metacharacters, which can then execute arbitrary commands if another user triggers the pipeline.
Root Cause: Poor Sanitization
The problem happens when branch names are directly used in scripts or as environment variables, without proper escaping or sanitization. This commonly happens in CI jobs that use the branch name, as illustrated below:
# Example .gitlab-ci.yml
deploy:
script:
- echo "Deploying branch $CI_COMMIT_REF_NAME"
- ./deploy.sh $CI_COMMIT_REF_NAME
If $CI_COMMIT_REF_NAME (the branch name) contains characters like ;, &&, or backticks, it can break out of the command and execute arbitrary shell instructions.
`
git checkout -b 'main; touch /tmp/pwned #'
`
The branch name here is: main; touch /tmp/pwned #
Push the Branch and Trick a User
The attacker pushes this branch to the repository and convinces another user (with higher privileges, or just someone who will trigger the pipeline) to run a pipeline for this branch—either via a Merge Request or directly.
`bash
./deploy.sh main; touch /tmp/pwned #
`
This runs both deploy.sh main and (unexpectedly) touch /tmp/pwned, creating a file—proof the code injection succeeded.
Let's use a .gitlab-ci.yml that would be vulnerable
# .gitlab-ci.yml
job:
script:
- echo "Processing $CI_COMMIT_REF_NAME"
- bash -c "echo Deploying $CI_COMMIT_REF_NAME"
- bash -c "./deploy.sh $CI_COMMIT_REF_NAME"
With the malicious branch name, the job will effectively run
bash -c "./deploy.sh main; touch /tmp/pwned #"
The command after the ; is executed as the same user running the pipeline—a big problem if that's an admin or a production runner.
Availability: Filesystems or apps could be deleted, DoS caused
Any CI/CD runner, especially ones handling deployments or sensitive environments, would be at risk.
Upgrade GitLab Runner to at least 15.3.5, 15.4.4, or 15.5.2 (or later).
Sanitize User Input
- Never pass untrusted variables (like $CI_COMMIT_REF_NAME) directly to shell commands unless sanitized or quoted properly.
script
- echo "Processing ${CI_COMMIT_REF_NAME//[^a-zA-Z-9_-]/}"
Restrict Runner Permissions
- Use locked-down runners for trusted branches, and don't allow arbitrary code from feature branches to run on production runners.
References and Further Reading
- GitLab Security Release for CVE-2022-2251
- NVD Details - CVE-2022-2251
- GitLab Runner Documentation
- Bugbountywriteup: Exploiting CVE-2022-2251
Summary
CVE-2022-2251 is a strong reminder to never trust user input—even something as innocuous as a branch name. If you haven't upgraded or checked your scripts, do it now—before an attacker does.
Timeline
Published on: 01/17/2023 21:15:00 UTC
Last modified on: 01/25/2023 03:34:00 UTC