Rules / GL032
GL032 SSH private key written to file via echo
Severity: warn
OWASP: CICD-SEC-6 – Insufficient Credential Hygiene
What glsec checks
glsec flags script lines that use echo or printf to write what appears to be an SSH private key to a file — specifically: lines that redirect or pipe to a .ssh/ path, or that reference a CI variable whose name contains PRIVATE or _KEY. When debug tracing is active (set -x or CI_DEBUG_TRACE), the shell prints the expanded variable value — including the full private key — to the job log. GitLab explicitly warns: "Never run a command like cat or tee on the variable because the SSH key is not masked if it appears in the job log."
The variable-name branch also catches non-SSH private credentials ($GCP_SERVICE_ACCOUNT_KEY, etc.), since the same debug-trace exposure applies; the finding message is therefore phrased generically.
Not flagged:
- Public / host keys — variables whose name contains
PUBLICorHOST(e.g.$ATTIC_PUBLIC_KEY,$SSH_HOST_KEY) are not secret. - Non-key
.ssh/files — writing into~/.ssh/config,~/.ssh/known_hosts, or~/.ssh/authorized_keys(configuration / public keys), e.g.echo "StrictHostKeyChecking no" >> ~/.ssh/config. Disabling host-key checking that way is a separate concern caught by GL048.
Trigger example
before_script:
- echo "$DEPLOY_SERVER_PRIVATE_KEY" | tr -d '\r' > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
Safe alternative
Use a GitLab file-type variable: GitLab writes the key to a file and the variable holds only its path, so a trace shows the path, not the key.
deploy:
before_script:
- eval $(ssh-agent -s)
- chmod 400 "$SSH_PRIVATE_KEY_FILE"
- ssh-add "$SSH_PRIVATE_KEY_FILE"
script:
- ./deploy.sh
With a plain variable, feed it to ssh-add through a here-string. set -x doesn't print redirections, so the trace shows + tr -d '\r' and + ssh-add -:
deploy:
before_script:
- eval $(ssh-agent -s)
- tr -d '\r' <<< "$SSH_PRIVATE_KEY" | ssh-add -
script:
- ./deploy.sh
Here-strings need bash; in an image whose shell is plain sh (Alpine, BusyBox), use a here-document instead. Piping echo "$SSH_PRIVATE_KEY" into ssh-add - is not enough: set -x prints the echo command with the key expanded.
References
- GitLab docs: Using SSH keys with GitLab CI/CD
- GL021: secret variable printed to log via
echo/printf - GL030:
ssh-keyscanexecuted dynamically (MITM risk) - GL033:
CI_DEBUG_TRACEenabled in committed pipeline YAML
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