CI/CD security best practices protect the automation that builds, tests, packages, signs, and deploys software. A CI/CD pipeline can mint cloud credentials, publish packages, update infrastructure, and deploy production. That makes pipeline YAML, runners, artifacts, caches, and release jobs part of your trusted computing base.

This CI/CD security guide is platform-agnostic. Use it for GitHub Actions, GitLab CI/CD, Jenkins, CircleCI, Buildkite, Azure DevOps, TeamCity, and custom release systems.

CI CD security best practices checklist

Start with the controls that reduce the most supply chain risk:

  • Set pipeline tokens to least privilege by default.
  • Declare permissions explicitly at the workflow or job level.
  • Separate untrusted pull request builds from privileged release jobs.
  • Pin third-party actions, plugins, images, and reusable workflows.
  • Use OIDC and short-lived cloud credentials instead of static secrets.
  • Scope secrets to jobs, environments, and approvals.
  • Harden self-hosted runners and avoid them for untrusted public PRs.
  • Treat artifacts and caches as untrusted when crossing trust boundaries.
  • Scan source code, dependencies, secrets, containers, and IaC in pull requests.
  • Require CODEOWNERS review for workflow and deployment changes.
  • Generate SBOMs and provenance for release artifacts.
  • Monitor pipeline changes, runner registrations, and blocked policy events.

If your immediate focus is GitHub, read the dedicated GitHub Actions security checklist. If your focus is static analysis rollout, read how to integrate static analysis tools into CI/CD.

1. Make pipeline permissions least privilege

Default tokens should be read-only or disabled unless a job needs write access. Grant permissions per job, not globally.

permissions: {}

jobs:
  test:
    permissions:
      contents: read
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@<pinned-sha>
      - run: npm ci && npm test

The principle applies outside GitHub too. Jenkins service accounts, GitLab job tokens, cloud deploy roles, registry credentials, and package publishing tokens should be scoped to the exact operation.

2. Separate untrusted builds from privileged releases

Untrusted code should not run in the same context as production secrets or write tokens. This is the core lesson behind many poisoned pipeline execution attacks.

Safer design:

  1. Run tests and advisory scans on untrusted pull request code with read-only permissions.
  2. Publish only safe metadata or signed artifacts.
  3. Run privileged release jobs from protected branches, protected tags, or approved environments.
  4. Re-check the source revision and artifact integrity before deployment.

Do not let fork pull requests, issue comments, branch names, PR titles, or artifact contents reach privileged shell execution without validation.

3. Pin actions, plugins, images, and reusable workflows

CI/CD pipeline security depends on what the pipeline executes. Tags and branches can move. Package registries can be abused. Maintainer accounts can be compromised.

Practical controls:

  • pin third-party GitHub Actions to full commit SHAs;
  • pin container images by digest for release jobs;
  • review Jenkins/GitLab plugins and update through change control;
  • allowlist trusted reusable workflows;
  • use dependency update PRs to refresh pins;
  • apply minimum release age policies where package managers support them.

Mutable dependencies are convenient, but immutable references are safer for privileged automation.

4. Use OIDC instead of long-lived cloud secrets

OIDC lets CI/CD jobs exchange a short-lived identity token for cloud credentials at runtime. This removes static AWS, Azure, or GCP keys from CI secrets.

Strong OIDC trust policies restrict by:

  • repository or project;
  • branch or tag;
  • workflow file;
  • protected environment;
  • audience;
  • subject pattern.

Grant id-token or equivalent only to jobs that need it. Pair OIDC with environment approvals for production.

5. Protect secrets in jobs and logs

Secrets should be passed only to the step that needs them. Avoid job-wide environment variables for high-value credentials.

Bad patterns:

  • echoing secrets for debugging;
  • passing secrets as command-line arguments;
  • using secrets: inherit broadly;
  • uploading .env files as artifacts;
  • storing production credentials in repository-level secrets used by every branch;
  • printing transformed secrets that log masking may not catch.

Use Corgea secrets scanning to catch leaked credentials before they spread through commits, branches, logs, and artifacts.

6. Harden runners

Hosted ephemeral runners reduce persistence risk. Self-hosted runners require much more care.

Runner security best practices:

  • do not use persistent self-hosted runners for public fork PRs;
  • use ephemeral or just-in-time runners for sensitive jobs;
  • separate runner groups by trust level;
  • restrict network egress from sensitive runners;
  • patch runner images and installed tools;
  • prevent one job from reading another job’s workspace;
  • monitor new runner registrations and unusual job execution.

If a runner can deploy production, treat it like production infrastructure.

7. Treat artifacts and caches as trust boundaries

Artifacts and caches can carry attacker-controlled files between jobs and workflows.

Controls:

  • avoid broad uploads such as path: .;
  • exclude .env, private keys, test credentials, and generated config;
  • validate filenames and formats before use;
  • extract untrusted archives outside the workspace;
  • do not use caches in privileged release jobs unless you trust the cache source;
  • make release jobs rebuild or verify artifacts from protected source.

A safe artifact flow is explicit, narrow, and verifiable.

8. Add security scanning where developers review code

CI/CD security best practices should include scanning the code and configuration that the pipeline is about to ship:

Start with pull request feedback. Developers are most likely to fix issues while the context is fresh.

9. Tune security gates by signal

Failing every build for every scanner finding is how AppSec programs lose trust. Failing no builds is how preventable incidents ship.

Good release-blocking candidates:

  • leaked secrets;
  • critical vulnerabilities in reachable code paths;
  • public cloud exposure created by IaC;
  • privileged containers in production manifests;
  • package publishing from an untrusted branch;
  • unsigned release artifacts where signing is mandatory.

Run noisy or new checks in advisory mode first. Tighten gates after false positives are handled. For more on signal, read how to reduce false positives in SAST.

10. Secure release workflows

Release jobs have the highest blast radius. They may publish packages, sign artifacts, deploy cloud infrastructure, or update production.

Release controls:

  • run only from protected branches, tags, or approved environments;
  • require human approval for production;
  • use short-lived credentials;
  • verify artifact checksums and provenance;
  • generate SBOMs;
  • sign packages and images where supported;
  • block mutable third-party dependencies in the release path;
  • log release metadata for incident response.

Do not let a test workflow automatically become a release workflow because it has convenient access to credentials.

11. Review pipeline changes like application code

Workflow YAML is code. It should have owners, review requirements, and scanning.

Add CODEOWNERS coverage for:

  • .github/workflows/;
  • .gitlab-ci.yml;
  • Jenkinsfiles;
  • Buildkite pipelines;
  • deployment scripts;
  • Terraform and Kubernetes release directories;
  • package publishing configuration.

Security review should focus on triggers, permissions, secrets, third-party dependencies, artifact flow, and release authority.

12. Monitor and respond

Detection matters because CI/CD incidents often move fast.

Monitor:

  • workflow file changes;
  • new secrets and secret access changes;
  • runner registrations;
  • failed attempts to use blocked actions or plugins;
  • unexpected package publishing;
  • unusual cloud role assumptions from CI;
  • public repository or fork settings changes.

Maintain an incident playbook that covers disabling workflows, revoking tokens, rotating secrets, invalidating artifacts, removing malicious releases, and reviewing runner state.

Try Corgea scanning in your CI/CD pipeline

Want CI/CD security best practices embedded in every pull request and pipeline?

Try Corgea today or book a custom demo for your CI/CD pipelines.

If you are comparing CI/CD and AppSec scanning options, read Corgea vs GitHub Advanced Security, Corgea vs Snyk, Corgea vs Checkmarx, and Corgea vs Semgrep. If your team is evaluating AI code review in pipelines, also see Corgea vs Claude Code Security.

FAQ

What are the most important CI/CD security best practices?

The most important CI/CD security best practices are least-privilege tokens, separating untrusted builds from privileged release jobs, using OIDC instead of long-lived secrets, pinning third-party actions or plugins, hardening runners, protecting artifacts and caches, and scanning code, dependencies, secrets, containers, and IaC in pull requests.

How does OIDC improve CI/CD security?

OIDC lets pipelines request short-lived cloud credentials at runtime instead of storing long-lived keys as CI secrets. Trust policies can restrict access by repository, branch, workflow, environment, and audience.

Should security scans fail CI/CD builds?

Security scans should fail builds for well-tuned, high-confidence policies such as leaked secrets, critical reachable vulnerabilities, unsafe infrastructure changes, or release-blocking container risk. Start with advisory mode for noisy checks, then tighten gates as signal improves.

Can Corgea run in CI/CD pipelines?

Yes. Corgea integrates security scanning into developer workflows and CI/CD so teams can scan application code, dependencies, secrets, containers, and infrastructure before risky changes merge.