eastbaycyber

CI/CD Security Hardening Checklist

Glossary 6 min read
EC
East Bay Cyber Editorial Team Reviewed 2026-05-16
Definition

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.sock unless 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

Software Supply Chain Security

Protecting code, dependencies, build systems, and distribution channels from tampering.

SAST / DAST / SCA

Static analysis, dynamic testing, and dependency scanning used as pipeline controls.

SBOM (Software Bill of Materials)

Machine-readable component inventory for vulnerability response and provenance.

Artifact Signing / Provenance

Cryptographic proof an artifact was built by a specific pipeline from a specific source.

OIDC Workload Identity (Federation)

Short-lived credentials issued to CI jobs, reducing long-lived keys.

Ephemeral Runners

Short-lived build agents destroyed after jobs complete.

Policy-as-Code / Admission Control

Enforceable rules (often Kubernetes) that block unsigned/non-compliant deploys.

Least Privilege (RBAC)

Restricting who can trigger workflows, access secrets, approve releases, and deploy.

Last verified: 2026-05-16

Disclaimer: This article may contain affiliate links. We earn a commission on qualifying purchases at no extra cost to you.