Skip to content
Techsense Developers
TrustLet's Talk
Insights
Cybersecurity & Compliance8 min readOct 2, 2026

A Step-by-Step Guide to Implementing a Secure-by-Design CI/CD Pipeline

A secure CI/CD pipeline is one where security controls are embedded at every stage of the software delivery lifecycle, from the moment code is committed to the instant it reaches production, rather…

A secure CI/CD pipeline is one where security controls are embedded at every stage of the software delivery lifecycle, from the moment code is committed to the instant it reaches production, rather than bolted on as a final gate. To build one, you integrate automated checks, enforce least-privilege access on the pipeline itself, verify artifact integrity, and treat your pipeline configuration as a first-class security asset. This guide walks through the concrete steps to do exactly that, with examples you can adapt to GitHub Actions, GitLab CI, or Jenkins.

If your team is shipping fast but reviewing security late, you already know the cost: a vulnerability caught in staging is cheap, while one caught by an external researcher after release is not. The goal here is to move those discoveries as far left as possible without grinding delivery to a halt.

Why Secure-by-Design Beats Security-as-an-Afterthought

Most pipelines start their lives as plumbing. Someone wires up a build, adds a test stage, and pushes to a registry. Security arrives later, usually after an incident or an audit. That retrofit approach leaves gaps because the controls were never part of the original design.

Secure-by-design flips that order. You assume the pipeline will be targeted, that dependencies will contain known vulnerabilities, and that credentials will leak if you let them. Then you design controls to make those failures survivable. The core secure-by-design principles that apply to CI/CD are:

  • Least privilege by default. Every job, token, and runner gets the minimum access it needs and nothing more.
  • Fail closed. When a security check cannot run, the pipeline stops rather than waving the build through.
  • Verifiable provenance. You can prove what built an artifact, from which commit, using which dependencies.
  • Defense in depth. No single control is trusted to catch everything.

These principles are the foundation. The steps below make them operational.

Step 1: Secure the Pipeline Before You Secure the Code

A common mistake is scanning application code while leaving the pipeline itself wide open. Your CI/CD system can push to production, so treat it like production.

Start with these controls:

  • Scope tokens tightly. In GitHub Actions, set the default GITHUB_TOKEN permissions to read-only and grant write access only where a job needs it.
permissions:
  contents: read

jobs:
  publish:
    permissions:
      contents: read
      packages: write
  • Pin third-party actions to a commit SHA, not a floating tag. Tags can be moved; a SHA cannot.
# Risky: a tag can be repointed to malicious code
- uses: some-org/some-action@v3

# Safer: pin to an immutable commit
- uses: some-org/some-action@a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0
  • Isolate runners. Ephemeral runners that are destroyed after each job limit the blast radius of a compromise. Avoid long-lived self-hosted runners that accumulate state and secrets.
  • Require signed commits on protected branches so you can attribute every change to a verified identity.

Step 2: Shift Security Left into the Developer Workflow

Shift-left security means catching problems where they are cheapest to fix: on the developer's machine and in the pull request. The earlier a finding surfaces, the less context-switching it costs to resolve.

Put the first line of defense in pre-commit hooks so secrets and obvious issues never reach the remote at all:

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.18.0
    hooks:
      - id: gitleaks

Then reinforce it in the pipeline, because local hooks can be skipped. The goal is a layered approach: developers get fast feedback locally, and the pipeline enforces the same rules without exception. This is one of the most practical DevSecOps best practices you can adopt, because it changes behavior without adding a dedicated review bottleneck.

Step 3: Add Automated Security Testing to Every Stage

Automated security testing is the engine of a secure pipeline. Each category of test catches a different class of problem, so you want several running in parallel.

Static Application Security Testing (SAST)

SAST analyzes source code for insecure patterns without running it. Run it on every pull request so findings are tied to the change that introduced them.

sast:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@...
    - name: Run Semgrep
      run: semgrep ci --config auto

Software Composition Analysis (SCA)

Most of your codebase is other people's code. SCA inventories your dependencies and flags known vulnerabilities, typically against the National Vulnerability Database. Tools like OWASP Dependency-Check and Trivy do this well.

sca:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@...
    - name: Scan dependencies
      run: trivy fs --exit-code 1 --severity HIGH,CRITICAL .

The --exit-code 1 is what makes this fail closed. A HIGH or CRITICAL finding breaks the build.

Secret Scanning

Credentials committed by accident are a leading cause of breaches. Run a secret scanner across the full history, not just the diff, because old leaks remain exploitable.

Dynamic Application Security Testing (DAST)

DAST probes a running instance of your application for issues that only appear at runtime, such as misconfigured headers or injection points. Run it against a deployed staging environment:

dast:
  runs-on: ubuntu-latest
  steps:
    - name: Run OWASP ZAP baseline scan
      run: |
        docker run -t owasp/zap2docker-stable zap-baseline.py \
          -t https://staging.example.com

Container and IaC Scanning

If you ship containers or provision with Terraform, scan those too. A hardened app on a vulnerable base image is still vulnerable. Trivy and Checkov cover container images and infrastructure-as-code respectively.

Step 4: Manage Secrets the Right Way

Hardcoded secrets are the fastest path to compromise. The rule is simple: no secret in source, no secret in logs, no long-lived secret in the pipeline.

  • Use a dedicated secrets manager such as HashiCorp Vault, AWS Secrets Manager, or your platform's native encrypted secrets store.
  • Prefer short-lived, dynamically issued credentials over static keys. OpenID Connect (OIDC) lets a pipeline authenticate to a cloud provider without storing any long-lived credential at all.
permissions:
  id-token: write
  contents: read

steps:
  - name: Configure AWS via OIDC
    uses: aws-actions/configure-aws-credentials@...
    with:
      role-to-assume: arn:aws:iam::123456789012:role/ci-deploy
      aws-region: us-east-1
  • Mask secrets in logs and audit periodically to confirm nothing is leaking through verbose output.

Step 5: Enforce Policy as Code and Artifact Integrity

To make controls non-negotiable, express them as policy as code. Open Policy Agent (OPA) and its Rego language let you gate deployments on conditions like "no CRITICAL CVEs" or "image must be signed."

Equally important is supply chain integrity. Generate a Software Bill of Materials (SBOM) for every build, and sign your artifacts so consumers can verify provenance.

# Generate an SBOM
syft packages dir:. -o spdx-json > sbom.json

# Sign a container image
cosign sign --yes registry.example.com/app:1.4.2

Referencing frameworks such as SLSA (Supply-chain Levels for Software Artifacts) gives you a maturity model to target. You do not need to reach the highest level immediately; pick the next tier and move toward it.

Step 6: Monitor, Measure, and Close the Loop

A pipeline is not secure once and forever. Dependencies gain new CVEs, and configurations drift. Treat security as a continuous loop:

  • Centralize findings so a vulnerability in staging and one in production land in the same queue with the same severity rules.
  • Track meaningful metrics: mean time to remediate, percentage of builds passing security gates, and the age of the oldest unresolved HIGH finding.
  • Rescan on a schedule, not just on commit, so a dependency that becomes vulnerable overnight is caught the next morning.

For teams that need this operationalized across multiple products, our security and platform engineering capabilities outline how continuous controls map to delivery workflows. Requirements also vary by sector, and our work across regulated and high-assurance industries reflects how compliance obligations shape pipeline design.

A Practical Rollout Order

Do not try to implement everything at once. A sensible sequence:

  1. Lock down pipeline permissions and pin actions.
  2. Add secret scanning and pre-commit hooks.
  3. Introduce SCA, since known-vulnerable dependencies are the most common finding.
  4. Layer in SAST, then DAST and container scanning.
  5. Add secrets management with OIDC.
  6. Formalize policy as code, SBOMs, and signing.
  7. Wire up centralized monitoring and metrics.

Each step delivers value on its own, so you reduce risk continuously rather than waiting for a big-bang rollout.

FAQ

What is the difference between shift-left security and DevSecOps?

Shift-left security is a tactic: move checks earlier in the lifecycle so issues are cheaper to fix. DevSecOps is the broader cultural and operational model that makes security a shared responsibility across development and operations. Shift-left is one of the practices that a DevSecOps program relies on.

Will adding security gates slow down my pipeline?

It can, if configured poorly. The fix is to run fast checks (SAST, secret scanning, SCA) in parallel on pull requests, and reserve slower checks (full DAST, deep container scans) for later stages or scheduled runs. Caching dependency scans and failing only on HIGH and CRITICAL severities keeps feedback fast while still catching serious issues.

How do I avoid overwhelming developers with false positives?

Tune your tooling. Start with high-confidence, high-severity rules, suppress known-acceptable findings with documented justifications, and route results into the existing pull request workflow rather than a separate dashboard. Treating noise as a bug to be fixed, not an inevitability, keeps the signal credible.

Do I need to sign artifacts and generate an SBOM for internal-only software?

Provenance controls are valuable even for internal software, because they let you answer "what is affected?" quickly when a new vulnerability lands in a widely used dependency. Signing and SBOMs are not only for public distribution; they are the backbone of incident response at scale.

Which security test should I implement first?

Software Composition Analysis, in most cases. The majority of real-world vulnerabilities enter through third-party dependencies, and SCA tooling is low-effort to adopt and produces immediately actionable results tied to specific packages and fix versions.