Supply-chain attacks target the pipeline, not just the application — a compromised dependency, a stolen deploy token, or a tampered build step can ship malicious code without ever touching the source repository a reviewer actually read. Three frameworks give teams a shared, non-vendor-specific vocabulary for defending against this: OWASP’s Top 10 CI/CD Security Risks, the SLSA (Supply-chain Levels for Software Artifacts) specification, and NIST’s Secure Software Development Framework (SP 800-218, SSDF). This checklist translates them into concrete controls you can actually implement.
At a Glance
| Risk Category | Core Control | Why It Matters |
|---|---|---|
| Dependency / supply-chain abuse | Pin dependencies to exact versions or hashes; generate an SBOM | Unpinned or unverified dependencies let attackers slip malicious code in through a routine update (OWASP CICD-SEC-3) |
| Pipeline execution hijacking | Treat pipeline config files (and anything they can trigger) as code requiring review; restrict what forked-PR workflows can run | Attacker-controlled pipeline definitions can run arbitrary commands with the pipeline’s privileges (OWASP CICD-SEC-4, “Poisoned Pipeline Execution”) |
| Identity & access | Least-privilege, short-lived, scoped credentials for every runner and service account | Overly broad or long-lived pipeline credentials are a top target once an attacker gets any foothold (OWASP CICD-SEC-2, CICD-SEC-6) |
| Artifact integrity | Sign commits and build artifacts; verify signatures before deploy | Without verification, a tampered artifact is indistinguishable from a legitimate one (OWASP CICD-SEC-9) |
| Build provenance | Generate signed provenance describing how an artifact was built (SLSA Build track) | Lets consumers verify an artifact came from the expected source and build process, not a tampered one |
| Secrets management | Centralized secrets manager, no plaintext secrets in config or environment files, automatic rotation | Leaked long-lived credentials are one of the most common real-world pipeline breach vectors |
| Logging & visibility | Centralized, tamper-resistant logs of every pipeline run and who triggered it | Without logs, a compromise can go undetected indefinitely (OWASP CICD-SEC-10) |
Dependency and Supply-Chain Controls
Most real-world software supply-chain incidents start with a dependency, not a hand-written line of code. OWASP’s Top 10 CI/CD Security Risks names this “Dependency Chain Abuse” (CICD-SEC-3): attackers compromise or impersonate a package your build pulls in, and your pipeline happily builds it into your release.
- Pin dependencies to exact versions, and where your package ecosystem supports it, to a content hash — not a floating version range.
- Generate a Software Bill of Materials (SBOM) for every build so you can quickly answer “are we affected?” when a new CVE breaks.
- Vet new and updated third-party components before they’re approved for use, per NIST SSDF practice PW.4 (“Reuse Well-Secured Software”), rather than letting any package anyone adds get built automatically.
- Mirror or proxy public package registries internally so a registry-level compromise or a removed package can’t silently break or poison your builds.
Trade-off: strict pinning slows down picking up security patches automatically — you need a deliberate, scheduled update process (with automated vulnerability scanning) rather than relying on floating versions to “self-heal,” which is itself an attack surface.
Pipeline Execution and Configuration
OWASP calls out “Poisoned Pipeline Execution” (CICD-SEC-4) as a distinct risk: if an attacker can modify the pipeline definition itself — a CI config file, a build script, an included template — they can make the pipeline run arbitrary commands with whatever privileges that pipeline holds, often including access to production secrets.
- Require code review on any change to pipeline configuration files, exactly as you would for application code.
- Run workflows triggered by forked-repository pull requests with no access to secrets, or require explicit maintainer approval before they run at all.
- Disallow pipeline steps from being defined by untrusted, dynamically fetched content at build time.
- Address “Insufficient Flow Control” (CICD-SEC-1) by enforcing required approvals/gates between code merge and production deploy — a pipeline that can push straight from an unreviewed commit to production has no human check left in the loop.
Identity, Access, and Secrets
OWASP groups several related risks here: “Inadequate Identity and Access Management” (CICD-SEC-2), “Insufficient PBAC / Pipeline-Based Access Controls” (CICD-SEC-5), and “Insufficient Credential Hygiene” (CICD-SEC-6). The common thread is that pipelines, build agents, and service accounts routinely get more access than the specific job they run actually needs, and that access doesn’t expire on its own.
- Give each runner and service account the minimum scope needed for its specific job — a job that only needs to read one repository should not hold a token that can push to all of them.
- Prefer short-lived, automatically rotated credentials (OIDC-based cloud role assumption, for example) over static API keys and tokens.
- Store secrets exclusively in a dedicated secrets manager, never in plaintext environment variables, config files, or source control.
- Separate credentials and access between non-production and production pipelines; a compromised staging pipeline shouldn’t be able to reach production deploy keys.
This also maps directly onto NIST SSDF’s “Prepare the Organization” group, specifically PO.5, which calls for separating and hardening development, build, test, and distribution environments rather than running everything on shared, loosely controlled infrastructure.
Artifact Integrity and Build Provenance
“Improper Artifact Integrity Validation” (OWASP CICD-SEC-9) covers the gap where a build output is deployed without any check that it’s actually the artifact the pipeline produced, unmodified. The SLSA framework (slsa.dev) gives this a formal, incremental structure through its Build track levels:
- SLSA Build L1: provenance (metadata describing how the artifact was built) exists and is distributed, but it isn’t signed — useful for catching honest mistakes, not for stopping a determined attacker.
- SLSA Build L2: builds run on a dedicated, hosted build platform (not a developer’s laptop), and the provenance is cryptographically signed and tied to that platform — this is the level at which post-build tampering becomes detectable.
- SLSA Build L3: the build platform additionally isolates each build run from every other run and keeps the signing material inaccessible to user-defined build steps — this is the level that defends against tampering during the build itself, including by insiders or compromised build definitions.
Practical controls that implement this:
- Require signed commits so every change in history can be attributed to a verified identity (NIST SSDF PS.1).
- Sign build artifacts and container images, and enforce signature verification as a hard gate before deployment, not an optional check.
- Generate and publish cryptographic hashes or SLSA-format provenance for every release so downstream consumers (or your own deploy tooling) can verify it (NIST SSDF PS.2).
- Archive release artifacts and their provenance/SBOM data so a future vulnerability disclosure can be traced back to exactly which builds are affected (NIST SSDF PS.3).
Trade-off: SLSA L3-equivalent build isolation is meaningfully harder to operate than L1 or L2 — it typically means adopting a managed, ephemeral build platform rather than long-lived self-managed runners. Most teams are better served by reaching L2 broadly (signed provenance from a hosted, non-developer-machine build) before chasing L3 everywhere.
Third-Party Services and Logging
Two more OWASP risks round out the list: “Ungoverned Usage of 3rd Party Services” (CICD-SEC-8) — pipeline integrations and marketplace actions adopted without security review, each one a new potential access path into your build — and “Insufficient Logging and Visibility” (CICD-SEC-10), where a compromise can persist undetected simply because no one is watching pipeline activity closely enough to notice it.
- Maintain an approved allowlist of third-party CI actions/plugins, and pin them to a specific commit or version rather than a floating tag.
- Review the permissions any new third-party integration requests before approving it, the same way you’d review an OAuth app request.
- Centralize pipeline logs outside the CI system itself, so an attacker who compromises the CI platform can’t also erase the evidence.
- Alert on anomalous pipeline behavior — new secrets accessed, unusual deploy targets, runs triggered outside normal hours — rather than only reviewing logs after an incident.
Vulnerability Response
NIST SSDF’s “Respond to Vulnerabilities” (RV) group is the piece teams most often skip because it isn’t about prevention — it’s about what happens after something is found. RV.1 calls for gathering vulnerability information from public sources and researchers and maintaining a disclosure policy; RV.2 calls for assessing and remediating each one based on actual risk; RV.3 calls for root-cause analysis so the same class of issue doesn’t recur. A secure pipeline that can’t quickly answer “which of our artifacts contain this dependency” — which is exactly what an SBOM and build provenance are for — turns a routine disclosure into a multi-week fire drill. If you’re also managing AI-assisted development, our AI-generated code security review checklist covers the related question of reviewing code your pipeline builds but nobody fully hand-wrote.
The Checklist
- Dependencies pinned to exact versions or hashes, with an SBOM generated per build
- New/updated third-party components vetted before approval
- Pipeline configuration files reviewed like code, with no untrusted dynamic content executed at build time
- Forked-PR workflows blocked from secrets or gated behind maintainer approval
- Required approval gates between merge and production deploy
- Least-privilege, short-lived credentials per runner/service account; no static long-lived tokens where avoidable
- Secrets stored only in a dedicated secrets manager, never in plaintext config or source control
- Production and non-production pipeline credentials fully separated
- Commit signing required; signature verification enforced before merge where feasible
- Build artifacts signed, with signature verification as a hard gate before deployment
- Builds run on a dedicated, hosted build platform — not a developer workstation — targeting at least SLSA Build L2
- Release artifacts and provenance/SBOM data archived for future vulnerability lookups
- Third-party CI actions/plugins allowlisted and version-pinned
- Pipeline logs centralized outside the CI platform, with alerting on anomalous activity
- A documented vulnerability disclosure and response process, with root-cause analysis after remediation
Bottom Line
Securing a CI/CD pipeline against supply-chain attacks isn’t one control, it’s the accumulation of many small ones: pin what you depend on, treat pipeline config as code, scope credentials tightly, sign what you build, and log everything so a breach doesn’t stay invisible. OWASP’s Top 10 names the specific risks, SLSA gives you a concrete, incremental ladder for build integrity, and NIST’s SSDF ties it all into a broader secure-development lifecycle. None of these require buying a specific vendor’s product — they’re a checklist you can start implementing with the CI system you already have.
FAQ
What’s the single highest-priority control to start with?
Least-privilege, short-lived credentials for pipeline runners and service accounts. Overly broad, long-lived credentials are consistently the mechanism that turns a minor pipeline compromise into full production access.
What’s the difference between SLSA and an SBOM?
An SBOM (Software Bill of Materials) lists what components are in an artifact. SLSA provenance describes how the artifact was built — the build platform, process, and inputs — and, at higher levels, is cryptographically signed so it can’t be forged or altered after the fact. They’re complementary, not substitutes.
Do we need to reach SLSA Build L3 to be considered secure?
Not necessarily. L3 defends specifically against tampering during the build, including by insiders — a real but narrower threat than what L2 (signed provenance from a hosted build platform) already addresses. Most organizations get the majority of practical benefit by reaching L2 consistently before investing in L3’s build-isolation requirements.
Is dependency pinning enough to stop supply-chain attacks?
No. Pinning stops a dependency from silently changing out from under you, but it doesn’t catch a malicious package that was already malicious when you first pinned it. It needs to be paired with vetting new/updated components and scanning for known vulnerabilities on a deliberate schedule.
Where do these frameworks overlap?
Heavily. OWASP’s risks describe specific attack patterns in CI/CD systems; NIST’s SSDF describes organization-wide practices across the whole development lifecycle (of which pipeline security is one part); SLSA focuses narrowly and technically on verifying how a specific artifact was built. Using all three together covers the risk-identification, organizational-practice, and technical-verification angles respectively.
Sources
- OWASP Top 10 CI/CD Security Risks
- SLSA v1.2 — Build Track Levels
- NIST SP 800-218 — Secure Software Development Framework (SSDF) v1.1
Discover more from Software Online Review
Subscribe to get the latest posts sent to your email.
