- security
- devops
- ci-cd
- sast
- sbom
- devsecops
Secure SDLC Pipeline Guide: Baking Security Into Every Stage of CI/CD
Secure SDLC Pipeline Guide: Baking Security Into Every Stage of CI/CD
A secure software development lifecycle (secure SDLC) pipeline does not bolt security on at the end. It integrates automated controls at every stage — from the first commit to production deployment — so that vulnerabilities are caught before they can become incidents.
This guide walks through the practical components of a hardened CI/CD pipeline: static and dynamic analysis, dependency scanning, secrets detection, software bill of materials, artifact signing, and policy gates that enforce all of the above as a non-negotiable build step.
If you are building network-level controls alongside these pipeline controls, read our post on zero-trust architecture for startups — the two approaches are complementary and together cover both the delivery path and the runtime environment.
Why a Secure SDLC Pipeline Matters
Traditional security practice treated code review, penetration testing, and vulnerability scanning as phases that happened after software was written. This model has two fundamental weaknesses: findings arrive too late to be cheap to fix, and manual checkpoints cannot scale with the speed of continuous delivery.
A secure SDLC pipeline shifts these controls left — running them automatically, in parallel with development, with results surfaced in pull requests where the cost of remediation is lowest. Policy gates mean nothing reaches production unless the pipeline approves it.
The pipeline does not replace architectural security (see our services for threat modelling and infrastructure hardening), but it is the fastest return on security investment for most engineering teams.
Stage 1: Pre-Commit Controls
The fastest feedback happens before code leaves a developer's machine.
Secrets Detection
Hardcoded credentials, API keys, and connection strings are the most common cause of supply chain incidents. Scanning for them at commit time is inexpensive and highly effective.
Tools to consider: gitleaks, detect-secrets, truffleHog
Key configuration points:
- Run as a Git pre-commit hook so the developer sees the failure immediately.
- Maintain an allowlist for test fixtures that intentionally look like secrets (e.g., dummy example keys in documentation).
- Configure the baseline snapshot so only net-new findings block commits rather than re-surfacing old suppressed items on every run.
- Feed findings into your developer platform so suppression history is reviewable.
Linting and Dependency Lock Files
Pre-commit is also the right place to enforce lock file integrity. Require that package-lock.json, go.sum, or poetry.lock is committed alongside any change to the corresponding manifest. An unlocked dependency tree is an uncontrolled dependency tree.
Stage 2: Static Analysis (SAST)
Static application security testing runs on source code without executing it, flagging patterns that frequently correspond to vulnerabilities.
What SAST Catches
SAST tools target classes of defects that appear in source structure: SQL injection patterns, unsafe deserialization, hardcoded credential assignments, path traversal, command injection, and missing authorization checks are representative examples. They do not catch logic errors or runtime conditions.
Tools to consider: Semgrep (language-agnostic, rule-as-code), Checkmarx, Veracode, CodeQL (GitHub-native), SonarQube
Running SAST Efficiently in CI
Run SAST on every pull request, not only on the main branch. Scanning the diff rather than the full repository on each PR keeps runtimes short while still surfacing new findings before they merge.
Recommended pipeline structure:
- Check out the branch.
- Run SAST in parallel with unit tests (they are independent).
- Fail the pipeline on any finding above your configured severity threshold (typically
highandcritical). - Post findings as inline PR review comments to close the feedback loop with the author.
Suppress known-false-positives with structured rule comments in code (# nosec in Python, // nolint:gosec in Go) that are themselves reviewable and auditable.
Stage 3: Software Composition Analysis (SCA)
Your application's dependency graph is part of your attack surface. SCA scans that graph against known vulnerability databases (CVE, OSV, GitHub Advisory) and flags packages with unpatched vulnerabilities.
SCA in Practice
Tools to consider: trivy, Snyk, OWASP Dependency-Check, grype
Configure SCA to:
- Block on
criticalseverity CVEs with a CVSS score above a threshold your team defines (e.g., 9.0). - Generate a full dependency report as a CI artefact for audit purposes.
- Run on both application dependencies and base container images.
- Integrate with your issue tracker so findings automatically create tickets with the affected package, the fixed version, and the CVE reference.
Keep your threshold policy in version control alongside the pipeline definition. This makes the policy reviewable, diffable, and explainable to auditors.
Stage 4: Generating a Software Bill of Materials (SBOM)
A software bill of materials is a machine-readable inventory of every package and component in your build. It is increasingly required by enterprise customers, government procurement, and compliance frameworks such as NIST SP 800-218.
SBOM Formats
Two formats have emerged as standards:
- SPDX — an ISO/IEC standard with broad tooling support.
- CycloneDX — purpose-built for security use cases; richer vulnerability linking.
Generating and Attesting SBOMs in the Pipeline
# Example using syft (Anchore)
syft <image>:<tag> -o cyclonedx-json > sbom.json
# Attach the SBOM to the OCI image using ORAS
oras attach <image>:<tag> sbom.json:application/vnd.cyclonedx+json
Generate the SBOM at the point the final container image is built, then attach it to the image in the registry. Downstream tools can then retrieve and scan it without rebuilding.
Store SBOMs as signed artefacts (see Stage 5). An unsigned SBOM is only weakly useful because you cannot verify it describes the image you are running.
Stage 5: Artifact Signing and Supply Chain Integrity
Signing build outputs proves that a given artefact was produced by your pipeline from a specific source commit. An attacker who compromises a registry cannot insert an unsigned image without breaking verification.
Sigstore and Cosign
cosign (part of the Sigstore project) has become the practical standard for signing OCI images without managing long-lived signing keys.
Keyless signing with OIDC:
# Sign during CI — no key material stored; the signing certificate
# is bound to the CI job's OIDC identity token
cosign sign --yes <image>@<digest>
# Verify before deployment
cosign verify \
--certificate-identity "https://github.com/your-org/your-repo/.github/workflows/release.yml@refs/heads/main" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
<image>@<digest>
Keyless signing binds the certificate to the CI job's identity rather than to a stored private key, which eliminates key management as an attack surface.
Add verification as a step in your deployment pipeline or Kubernetes admission controller (e.g., Kyverno or OPA/Gatekeeper) so that only signed images from your pipeline can be admitted to the cluster.
Stage 6: Dynamic Analysis (DAST) and API Security Testing
Dynamic application security testing exercises the running application rather than the source. It catches issues that only manifest at runtime: authentication bypasses, broken access control, injection via HTTP parameters, and insecure deserialization patterns that SAST did not flag.
When and Where to Run DAST
DAST runs against a deployed environment, so it belongs later in the pipeline than SAST/SCA — typically against a staging or review environment spun up on every pull request.
Tools to consider: OWASP ZAP (automation-first with the zap.yaml plan API), Burp Suite Enterprise, nuclei
A lightweight ZAP scan in API mode:
docker run --rm \
-v $(pwd):/zap/wrk:rw \
ghcr.io/zaproxy/zaproxy:stable \
zap-api-scan.py -t https://staging.yourapp.io/openapi.json \
-f openapi -r zap-report.html
For microservices, maintain an OpenAPI spec per service and run the scan against the spec in contract mode. This is faster than a full crawl and produces actionable, targeted findings.
Stage 7: Policy Gates
Individual tools generate findings, but policy gates enforce what those findings mean for the build. Without a gate, a failing SAST scan is advisory; with a gate, it blocks the merge.
Open Policy Agent (OPA) for Pipeline Policy
OPA provides a general-purpose policy language (Rego) that can express complex rules: block if any critical CVE is unpatched for more than 30 days; block if the SBOM is absent; block if the image is unsigned; allow if all findings are suppressed with a named reason.
Store policies in the same repository as your pipeline definitions. This means policy changes go through code review, are auditable in git history, and can be tested against fixture inputs.
Minimum Viable Gate Configuration
Even without OPA, you can implement a useful gate with exit codes:
# Example: pipeline gate step
- name: Security gate
run: |
trivy image --exit-code 1 --severity CRITICAL $IMAGE
semgrep --error --config p/owasp-top-ten .
cosign verify $IMAGE_DIGEST
Each tool exits non-zero on failure; the step fails the build.
Putting It Together: Pipeline Order
A practical ordering that minimises wall-clock time:
| Stage | When | Blocks merge? |
|---|---|---|
| Secrets scan (pre-commit) | Before push | Yes |
| SAST + lint | PR opened | Yes |
| SCA (source + image) | PR opened (parallel to SAST) | Yes on critical |
| SBOM generation | After image build | No (artefact only) |
| Artifact signing | After image build | Yes if verification fails at deploy |
| DAST | After staging deploy | Yes on high+ |
| Policy gate | Before merge to main | Yes |
Run stages 3 and 4 in parallel with stage 2. The total pipeline time is bounded by the slowest parallel branch, not the sum.
Operationalising the Pipeline
Baseline First, Enforce Second
For teams adding a secure SDLC pipeline to an existing codebase, generate a baseline snapshot before enabling blocking mode. Suppress all current findings, enforce the policy that no new findings merge, and work down the backlog on a defined schedule. This avoids a wall-of-red that stalls adoption.
Developer Experience Matters
A security pipeline that is slow, noisy, or opaque will be worked around. Invest in:
- Fast feedback (most tools should complete within 3-5 minutes on a PR).
- Clear, actionable finding messages (link to the rule explanation and a fix example).
- A suppression workflow that is easy but auditable.
Treat Policy as Code
Every threshold, suppression, and exception in your pipeline should live in version-controlled files, reviewed by the same people who review application code. This makes your security posture an auditable artefact, not institutional memory.
Next Steps
A secure SDLC pipeline is one layer of a defence-in-depth posture. Pair it with:
- Runtime security: network segmentation and identity-aware access — covered in zero-trust architecture for startups.
- Infrastructure hardening: IaC policy scanning (Checkov, tfsec) applied to your Terraform before
apply. - Threat modelling: structured STRIDE/PASTA sessions for new features, before the first line of code.
If you want help designing or implementing a secure SDLC pipeline for your organisation — from tool selection to policy definition to developer enablement — get in touch with us at Cursopic or send us a message directly.
Need help with this?
Cursopic helps IT teams ship cloud-native software faster — from architecture to delivery.