CI/CD Security Hardening Checklist
A CI/CD security hardening checklist is a set of concrete controls that reduce the risk of pipeline compromise, build tampering, credential theft, and unauthorized releases. It applies to source control, build runners/agents, registries, and deployment tooling.
CI/CD security is a software supply-chain control point—if attackers compromise your pipeline, they can ship “your” software with their payload. This CI/CD security hardening checklist focuses on the highest-impact controls to protect runners, secrets, dependencies, artifacts, and deployments, with logging you can actually use for audits and incident response.
How it works (map controls to the pipeline flow)
A good checklist follows the CI/CD data flow:
developer commit → pipeline trigger → build/test → artifact publish → deploy
At each step you: - Reduce blast radius (isolation and least privilege) - Reduce credential exposure (secrets handling and short-lived tokens) - Validate inputs (dependencies, third-party actions/plugins) - Preserve integrity (signing + provenance) - Enforce approvals (deployment gates + policy)
Use this checklist in two modes: 1. Baseline hardening for all repos (org policies, templates, defaults) 2. High-risk hardening for release pipelines (prod deploy, signing keys, privileged infra)
Checklist (prioritized for impact)
1) Source control protections
- Require PRs + reviews for protected branches; block direct pushes.
- Enforce branch protection:
- Required status checks
- Required approvals
- Signed commits where feasible
- Lock down CI configuration changes (
.github/workflows/,.gitlab-ci.yml,Jenkinsfile) using CODEOWNERS. - Minimize who can create/modify secrets and who can approve environments.
- Disable or tightly control “workflow from fork” execution for sensitive repos.
2) Runner/agent hardening
- Prefer ephemeral, auto-rebuilt runners; avoid long-lived shared hosts.
- Run builds in isolated containers/VMs; restrict privileged builds.
- Treat the Docker socket as high-risk:
- Avoid mounting
/var/run/docker.sockunless you fully understand the escalation path. - Remove admin privileges; apply least-privilege OS permissions to build users.
- Restrict inbound access to runners and segment them from production networks.
- Patch runner images regularly; manage runner images like production assets.
- If using self-hosted runners, require:
- Dedicated runner pools by trust level (public repo vs private, prod vs non-prod)
- Automatic teardown after job completion
- Strong egress controls to reduce exfiltration
3) Secrets and tokens (credentials are the pipeline’s crown jewels)
- Use short-lived, scoped credentials:
- Prefer OIDC workload identity to cloud providers over static access keys.
- Store secrets in a managed secret store; rotate on schedule and on suspicion.
- Keep secrets out of logs:
- Enable secret masking
- Avoid
set -x(or equivalents) in release jobs - Separate tokens by purpose:
- Read-only tokens for checkout
- Separate publish/deploy credentials
- Never reuse personal access tokens for automation
- Audit secret access and changes; alert on new secret creation and high-privilege token issuance.
If your team also needs stronger credential hygiene outside CI, consider a team password manager (e.g., 1Password) to reduce ad-hoc secret sharing and improve rotation workflows: Try 1Password →. (Still use CI-native secret stores for pipelines—don’t pass long-lived secrets through chat or tickets.)
4) Dependency and build input control (reduce “untrusted inputs”)
- Pin dependencies and base images to immutable versions/digests.
- Scan dependencies (SCA) and container images:
- Fail builds on critical findings, with an explicit exception process (and expiry).
- Restrict outbound network where feasible to reduce:
- Dependency confusion
- Typosquatting pulls
- Data exfiltration from compromised build steps
- Validate third-party actions/plugins:
- Prefer vendor-published actions
- Pin versions (ideally to commit SHAs)
- Maintain an allowlist for permitted actions/plugins
5) Artifact integrity and provenance (make releases verifiable)
- Produce SBOMs for releases and store them with artifacts.
- Sign artifacts/images and verify signatures at deploy time.
- Use protected registries and enforce immutability for release tags.
- Capture provenance:
- Commit SHA
- Builder identity
- Build parameters
- Dependency inputs
- Ensure the release pipeline is separate from general CI and has tighter permissions.
6) Deployment gates and environment controls (stop bad releases from reaching prod)
- Require approvals for production environments; enforce separation of duties where possible:
- “Build” and “Deploy” roles shouldn’t always be the same group.
- Use policy-as-code / admission control:
- Only deploy signed images
- Require provenance attestations
- Enforce allowed registries and namespaces
- Test and automate rollbacks; a secure pipeline still needs a fast exit.
- Limit production credentials to deployment jobs only; no broad “CI can access prod” by default.
7) Logging, detection, and response (assume compromise is possible)
- Centralize audit logs from SCM and CI/CD; alert on high-risk events:
- Token creation
- Secret access/change
- Runner registration
- Pipeline definition changes
- Monitor for unusual publish/deploy patterns:
- New destinations (registries/accounts)
- Off-hours releases
- New or unexpected actors
- Pre-stage incident response playbooks:
- Revoke tokens immediately
- Rotate secrets
- Invalidate/quarantine artifacts
- Quarantine or rebuild runner pools
- Review deploy history and registry events for tampering
Implementation snippets (copy into tickets)
# 1) Pin GitHub Actions to immutable commit SHAs (avoid floating tags)
# In workflow YAML, use:
# uses: org/action@<commit_sha>
# 2) Detect secrets accidentally committed (example with gitleaks)
gitleaks detect --source . --no-git --redact
# 3) Generate an SBOM for a container image (example: syft)
syft packages docker:yourimage:1.2.3 -o spdx-json > sbom.spdx.json
# 4) Sign a container image (example: cosign keyless with OIDC where supported)
cosign sign --yes your-registry.example.com/app@sha256:<digest>
# 5) Verify signature during deploy or admission checks
cosign verify your-registry.example.com/app@sha256:<digest> \
--certificate-identity-regexp '.*' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com'
When you’ll encounter CI/CD hardening requirements
- Before a production go-live or compliance audit: You’ll need to prove you prevent unauthorized releases and can trace artifacts to source.
- After a credential leak or suspicious release: Hardening becomes immediate containment.
- During a platform migration: Best time to enforce org-wide templates and defaults.
- When enabling power features: Self-hosted runners, privileged Docker builds, dynamic environments, IaC deployments.
- When CI becomes a publisher: The moment CI can push to registries/package repos/cloud accounts, it becomes a high-value target.
Operationally, treat this like firewall standards: mandatory baseline + exceptions with expiry. If you can’t implement a control immediately (e.g., fully ephemeral runners), document compensating controls (tight permissions, egress restrictions, frequent rebuilds) and assign an owner + date.
Detection quick wins (example queries)
# Example SPL-style searches (adapt fields to your log source)
# 1) Detect workflow/pipeline definition changes on default branch
index=scm sourcetype=github:audit action IN ("repo.update", "workflow.create", "workflow.update")
| search (object IN (".github/workflows","Jenkinsfile",".gitlab-ci.yml")) OR (message="workflow" OR message="pipeline")
| stats count by actor, repo, action, object, src_ip
# 2) Detect secrets access / changes (GitHub audit examples vary by plan)
index=scm sourcetype=github:audit action IN ("org.update_secret", "repo.update_secret", "org.add_oauth_app", "org.add_member")
| stats count by actor, action, repo, src_ip
# 3) Detect unusual artifact publishing (CI logs or registry logs)
index=ci sourcetype=buildlogs ("docker push" OR "npm publish" OR "pip upload" OR "mvn deploy")
| stats count by repo, actor, pipeline_id, destination
Related terms
Protecting code, dependencies, build systems, and distribution channels from tampering.
Static analysis, dynamic testing, and dependency scanning used as pipeline controls.
Machine-readable component inventory for vulnerability response and provenance.
Cryptographic proof an artifact was built by a specific pipeline from a specific source.
Short-lived credentials issued to CI jobs, reducing long-lived keys.
Short-lived build agents destroyed after jobs complete.
Enforceable rules (often Kubernetes) that block unsigned/non-compliant deploys.
Restricting who can trigger workflows, access secrets, approve releases, and deploy.