A CI/CD pipeline has significant access — to your source code, deployment credentials, and often production infrastructure directly. Securing it properly is as important as securing the production servers it deploys to.
Why CI/CD Pipelines Are a High-Value Target
Compromising a CI/CD pipeline can give an attacker a path to inject malicious code directly into production, or steal the deployment credentials needed to access your infrastructure — often with less monitoring than production systems themselves receive.
1. Never Hardcode Secrets in Pipeline Configuration
Use your CI/CD platform's built-in secrets management (GitHub Secrets, GitLab CI/CD variables) rather than embedding credentials directly in workflow files:
# Wrong
- run: ssh user@server -p PlainTextPassword123 "deploy.sh"
# Correct
- run: ssh -i ${{ secrets.DEPLOY_KEY }} user@server "deploy.sh"
2. Use Dedicated, Restricted Deployment Credentials
Never use personal or broadly-privileged credentials for automated deployment — see How to Set Up a Deployment User with Restricted SSH Access for creating a properly scoped deployment account.
3. Restrict Which Branches/Events Can Trigger Deployment
on:
push:
branches: [main] # only main branch, not every branch
Prevent deployment triggers from arbitrary branches or, critically, from pull requests originating from forks (a common attack vector for public repositories).
4. Require Approval for Sensitive Workflows
Most CI/CD platforms support requiring manual approval before a workflow runs against production, especially for workflows triggered by external contributors — configure this for any pipeline with production deployment access.
5. Pin Action/Dependency Versions
# Risky - could change unexpectedly
- uses: some-action@main
# Safer - pinned to a specific, reviewed version
- uses: [email protected]
Using a mutable reference (like @main) for third-party actions means the code that runs in your pipeline could change without your knowledge or review.
6. Limit Self-Hosted Runner Exposure
See How to Set Up a Self-Hosted GitHub Actions Runner on a VPS — never use self-hosted runners for public repositories without strict controls, since anyone who can open a pull request could potentially execute code on your infrastructure.
7. Audit Third-Party Actions/Plugins Before Use
Review the source code of third-party CI/CD actions or plugins before adding them to your pipeline, especially ones with access to secrets — a malicious or compromised action can exfiltrate your secrets directly.
8. Rotate Deployment Credentials Regularly
Treat deployment keys/tokens the same as any other credential — rotate them periodically and immediately upon any team member departure or suspected exposure.
9. Scan Dependencies and Container Images in the Pipeline
- run: npm audit
- run: docker scout cves myimage:latest
See How to Audit and Secure Your Application's Dependencies for the broader practice, integrated directly into the pipeline so vulnerabilities are caught before deployment, not after.
10. Log and Monitor Pipeline Activity
Review who triggered deployments, when, and what changed — most CI/CD platforms provide this natively; ensure the logs are actually reviewed periodically, not just collected.
11. Separate Build and Deploy Permissions Where Possible
The job that builds/tests code doesn't necessarily need the same credentials as the job that deploys to production — scope secrets to only the specific jobs that genuinely need them.
12. Never Echo Secrets in Logs
# Never do this
- run: echo "Deploying with token ${{ secrets.API_TOKEN }}"
Most platforms automatically mask known secret values in logs, but avoid explicitly printing them regardless, and be cautious with debug output that might inadvertently expose them.
Quick Security Checklist
- No hardcoded secrets anywhere in pipeline configuration
- Dedicated, minimally-privileged deployment credentials
- Deployment restricted to specific trusted branches
- Third-party actions pinned to specific versions and reviewed
- Self-hosted runners isolated and restricted to trusted repositories
- Regular credential rotation
Continue Reading
- How to Set Up a Deployment User with Restricted SSH Access
- How to Set Up a Self-Hosted GitHub Actions Runner on a VPS
- How to Audit and Secure Your Application's Dependencies
Browse more articles in DevOps & CI/CD.
