Rules / GL030
GL030 ssh-keyscan executed dynamically in script (MITM risk)
Severity: warn
OWASP: CICD-SEC-7 – Insecure System Configuration
What glsec checks
glsec flags any script line that invokes ssh-keyscan. Running ssh-keyscan at pipeline runtime blindly trusts whatever public key the remote host presents at that moment. If the network path is compromised — shared runner network, DNS poisoning, or a rogue router — the runner will accept a fraudulent host key and the attacker can intercept the SSH session, including any secrets transmitted over it.
This pattern dominates GitLab CI SSH-deploy tutorials and is present in many real-world projects, despite GitLab's own SSH documentation explicitly warning against it.
Trigger example
before_script:
- mkdir -p ~/.ssh
- ssh-keyscan -H 'deploy.example.com' >> ~/.ssh/known_hosts
Safe alternative
Store a pre-verified known-hosts entry in a protected, masked CI variable and write it directly — no network call needed:
before_script:
- mkdir -p ~/.ssh
- echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts
- chmod 644 ~/.ssh/known_hosts
To obtain the entry: run ssh-keyscan <host> once from a trusted machine, verify the fingerprint out-of-band, then store the output as a CI variable named SSH_KNOWN_HOSTS.
References
- GitLab docs: Using SSH keys with GitLab CI/CD
- GL032: SSH private key written to file via
echo
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