Your CI/CD pipeline is one of the most privileged systems in your infrastructure. It accesses your source code, holds production credentials, deploys to live systems, and often has elevated permissions across cloud environments. A compromised pipeline can mean a compromised application, database, and cloud account simultaneously.
Yet pipeline security often receives far less attention than application security. This guide covers the practices that matter most.
Why CI/CD Security Is Critical
The SolarWinds attack demonstrated the catastrophic potential of pipeline compromise: attackers injected malicious code into a software build process, distributing backdoors to 18,000+ organizations through a trusted software update. The attack was undetected for months because the compromised code appeared legitimate.
Your pipeline doesn’t need to be SolarWinds to be a target. Any organization with:
- Credentials stored in CI/CD environment variables
- Automatic deployment to production on merge
- Write access to container registries
- Cloud provider credentials in the pipeline
…has a pipeline worth attacking.
1. Access Controls: Least Privilege
DevOps culture emphasizes shared ownership, but not everyone needs the same access. Define roles with minimum necessary permissions:
| Role | What they need |
|---|---|
| Developer | Trigger builds on their own branches |
| CI System | Read source code, write to artifact registry |
| CD System | Deploy to specific environments only |
| Security Engineer | Read build logs, scan results |
| Ops | Production environment management only |
The CI system should never have direct production database credentials — only the CD system needs deployment keys, and only for the environments it deploys to.
2. Secrets Management
Never store secrets in source code or as plain-text environment variables in CI configuration.
# WRONG: Secret visible in version-controlled config
env:
DATABASE_PASSWORD: "my-prod-password-123"
# CORRECT: Reference a secret from a vault
env:
DATABASE_PASSWORD:
from_secret: prod_database_password
Use your CI platform’s native secrets store (GitHub Actions Secrets, GitLab CI Variables with “Masked” and “Protected” flags, Jenkins Credentials). For more control, integrate with HashiCorp Vault or AWS Secrets Manager:
# GitHub Actions: retrieve secret from Vault
- name: Get secrets from Vault
uses: hashicorp/vault-action@v2
with:
url: https://vault.company.com
token: ${{ secrets.VAULT_TOKEN }}
secrets: |
secret/data/prod/db password | DB_PASSWORD
Rotate secrets on a schedule and immediately after any suspected exposure.
3. Build Environment Parity
Testing in an environment that doesn’t match production means security issues discovered in testing may not reflect production reality — and vice versa.
Use containers to standardize your build environment:
# Build image pins all tool versions
FROM ubuntu:22.04
RUN apt-get install -y \
openjdk-17-jdk=17.0.9+9-1 \
maven=3.8.7-1
Never use latest tags in build images — they can change without warning, introducing new vulnerabilities or breaking reproducible builds.
4. Scan Everything in the Pipeline
The pipeline should run security checks at multiple points:
# Example GitHub Actions security pipeline
jobs:
security:
steps:
# 1. Static analysis of application code
- name: SAST Scan
run: offensive360-scan --fail-on high
# 2. Dependency vulnerabilities
- name: Dependency Check
run: npm audit --audit-level=high
# 3. Container image scanning
- name: Image Scan
run: trivy image myapp:${{ github.sha }}
# 4. Infrastructure as Code scanning
- name: IaC Scan
run: checkov -d ./terraform
# 5. Secrets detection
- name: Secret Scan
run: gitleaks detect --source .
Make security failures block the build. A passing security pipeline should be a required check before merge.
5. Scan CI/CD Configuration Files Themselves
Attackers who compromise a repository can modify pipeline configuration files to exfiltrate secrets or inject malicious build steps. Treat your CI/CD config with the same scrutiny as application code:
- Require code review for changes to
.github/workflows/,Jenkinsfile,.gitlab-ci.yml - Use branch protection rules to prevent direct pushes to main
- Scan pipeline config files with dedicated IaC security tools
6. Secure the Software Supply Chain
Third-party dependencies are a significant attack surface. The event-stream npm attack (2018) and log4j (2021) demonstrated that popular, trusted packages can become attack vectors.
# Pin dependency versions (don't use floating ranges in production)
# package.json
"dependencies": {
"express": "4.18.2", // pinned — not "^4.18.0"
}
# Generate and commit a lockfile
npm install --package-lock-only
Use Software Composition Analysis (SCA) to continuously monitor your dependency tree for new CVEs:
- name: SCA Scan
run: |
npm audit --json > sca-report.json
# Fail on critical vulnerabilities
npm audit --audit-level=critical
7. Plan for Rollbacks
When a security issue is discovered in production, you need to roll back quickly. Build rollback capability into your deployment process from the start:
- Archive all build artifacts with immutable versioning
- Tag every deployment with the commit SHA and build number
- Test rollback procedures regularly (not just forward deployments)
- Automate rollback triggers on key monitoring alerts
8. Audit and Monitor
Log all pipeline activities and alert on anomalies:
- Who triggered builds and when
- Which secrets were accessed
- Deployment approvals and approvers
- Any failures or bypasses of security checks
Integrate pipeline audit logs into your SIEM. A build that runs at 3am on a weekend deserves automated scrutiny.
Summary Checklist
- Secrets stored in vault or CI native secrets store — never in code
- Least-privilege roles for all pipeline service accounts
- SAST, SCA, image scanning, and secrets detection in every pipeline
- Security failures block the build (not just warn)
- Branch protection requires security checks to pass before merge
- Pipeline config files reviewed like application code
- Pinned dependency versions with lockfiles
- Rollback procedure documented and tested
- Pipeline activity logged and monitored
A secure pipeline is the foundation of a secure software supply chain. Every vulnerability your pipeline catches is one that never reaches your users.