criticalExposed Secrets

SSH Private Key Committed to Version Control

What Is This Vulnerability?

An SSH private key file has been committed to a git repository. SSH keys provide direct authentication to servers, CI/CD systems, and code hosting platforms. An attacker with the private key can log into any server that trusts the corresponding public key, without needing a password, giving them full shell access.

Why It Happens

Developers sometimes store SSH keys in their project directory for deployment scripts or Docker builds and forget to add them to .gitignore. Automated provisioning scripts may generate key pairs in the working directory. Some Dockerfiles copy SSH keys for pulling private dependencies during the build process, and the key file ends up in the repository.

Example Code

VulnerableDockerfile
FROM node:20-alpine
WORKDIR /app
COPY . .
COPY id_rsa /root/.ssh/id_rsa
RUN chmod 600 /root/.ssh/id_rsa
RUN npm install
RUN rm /root/.ssh/id_rsa
CMD ["node", "server.js"]
FixedDockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN --mount=type=ssh npm install
COPY . .

FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app .
CMD ["node", "server.js"]

How Hackers Exploit It

Attackers extract the private key from the repository and use it to authenticate to any server where the matching public key is authorized. They gain full shell access, allowing them to steal data, install backdoors, pivot to internal networks, or disrupt services. Even if the key file is later removed from the repo, it remains in git history.

How to Fix It

Never place SSH private keys in your project directory. Add id_rsa, id_ed25519, and *.pem to your .gitignore. For Docker builds, use BuildKit SSH forwarding (RUN --mount=type=ssh) or multi-stage builds that do not include the key in the final image. If a key was committed, immediately revoke it by removing the public key from all authorized_keys files and generating a new key pair.

Frequently Asked Questions

Is the key still compromised if I delete it from the repo?
Yes. Git retains all file history, so the key can be recovered from previous commits. You must rewrite git history with tools like git filter-branch or BFG Repo-Cleaner, and even then, anyone who cloned the repo before the rewrite still has the key. Always generate a new key pair and revoke the old one.
How do I use SSH keys in Docker without committing them?
Use Docker BuildKit SSH agent forwarding with the --mount=type=ssh flag during the RUN step. This lets the build process use your local SSH agent without copying the key into the image. Alternatively, use multi-stage builds and ensure the final stage does not include any key material.
What key types should I use for SSH?
Ed25519 keys are recommended for modern deployments. They are shorter, faster, and more secure than RSA keys. If you need RSA compatibility, use at least 4096-bit keys. Avoid DSA and ECDSA with the NIST P-256 curve unless required by specific compliance requirements.
How can I prevent SSH keys from being committed?
Add common key filenames (id_rsa, id_ed25519, *.pem, *.key) to your .gitignore. Use pre-commit hooks with tools like detect-secrets or gitleaks to block commits containing private key patterns. Enable GitHub secret scanning to receive alerts if keys are pushed.

Related Security Topics

Check Your Code for This Vulnerability

Run a free scan to check if your site is affected by ssh private key committed to version control.