CI/CD pipelines now sit at the center of nearly every major supply chain breach of the last five years. SolarWinds' 2020 Sunburst attack compromised a single build server and reached roughly 18,000 downstream customers through one poisoned software update. In March 2025, attackers compromised the popular tj-actions/changed-files GitHub Action (CVE-2025-30066), injecting code that dumped CI secrets in plaintext logs across more than 23,000 repositories before it was caught. These weren't exotic zero-days — they exploited the same pipeline design flaws most teams still ship with today: over-privileged tokens, unscanned third-party actions, and no build provenance verification. A secure CI/CD pipeline isn't a checkbox item bolted on after a breach; it's a set of specific, testable controls applied at every stage — source, build, test, and deploy. This post walks through what those controls actually look like, with real incidents attached to each failure mode.
What makes CI/CD pipelines such a high-value target for attackers?
CI/CD pipelines are a high-value target because a single compromise gives attackers simultaneous access to source code, build secrets, and every downstream artifact a company ships — one foothold, many victims. The SolarWinds breach is the clearest example: attackers inserted the Sunburst backdoor into the Orion build process in September 2019, and it wasn't discovered until December 2020, by which point roughly 18,000 organizations, including multiple U.S. federal agencies, had pulled a trojanized update. More recently, the March 2025 tj-actions incident showed the same math at smaller scale but faster blast radius — a single compromised GitHub Action tag (v35.7.7) was pulled into tens of thousands of workflows within hours because CI configs referenced it by mutable tag rather than pinned commit SHA. Attackers increasingly treat the pipeline itself, not the production app, as the primary target.
Where do secure CI/CD pipelines most often fail first?
Secure CI/CD pipelines most often fail first at secrets management — static, long-lived credentials sitting in environment variables, config files, or third-party tooling that gets exfiltrated through logs or a compromised dependency. The Codecov Bash Uploader breach is the textbook case: attackers modified the uploader script on January 31, 2021, and it ran undetected inside thousands of customer CI pipelines for roughly two months before Codecov disclosed it on April 15, 2021, exfiltrating environment variables — including AWS keys, GitHub tokens, and database credentials — from every job that executed it. GitHub's own 2023 transparency report noted that leaked credentials remain one of the top root causes in reported incidents involving CI systems. The fix isn't "rotate more often" — it's removing static long-lived secrets from the pipeline entirely wherever short-lived, scoped alternatives exist.
How should you scope access for CI/CD identities and tokens?
You should scope CI/CD identities with short-lived, job-specific tokens issued through OIDC federation instead of static personal access tokens or cloud IAM keys stored as pipeline secrets. GitHub Actions' default GITHUB_TOKEN is scoped to contents: read unless a workflow explicitly requests more, but audits regularly find repositories granting contents: write or id-token: write pipeline-wide instead of per-job. The January 2023 CircleCI breach showed the downside of broad, durable access: a single engineer's laptop was compromised with session-token-stealing malware, and because CircleCI's internal systems held broadly scoped production access, the company had to advise every customer to rotate all secrets, tokens, and keys stored in the platform — not just the ones tied to the compromised account. Cloud-native OIDC (AWS, GCP, and Azure all support it natively with GitHub Actions and GitLab CI as of 2023) removes the durable-credential problem by issuing a token that's valid for the length of a single job run and nothing longer.
Why does dependency and SBOM scanning need to happen before merge, not after deploy?
Dependency and SBOM scanning needs to happen before merge because once a vulnerable or malicious package is built into an artifact, remediation means finding and rebuilding every downstream image that used it — a process that took most organizations weeks after Log4Shell (CVE-2021-44228, disclosed December 9, 2021) precisely because they had no SBOM to search against. The XZ Utils backdoor (CVE-2024-3094), discovered March 29, 2024, is the sharper recent example: a maintainer account compromised over roughly two years inserted a backdoor into liblzma versions 5.6.0 and 5.6.1, and organizations without dependency-graph visibility had no fast way to confirm whether a given build had pulled in the affected versions. A secure pipeline generates an SBOM (CycloneDX or SPDX format) as a build artifact on every run and diffs it against known-vulnerable and known-malicious package lists at the pull-request stage — before the artifact is signed and pushed, not during an incident response scramble six months later.
How do you verify that a pipeline's build output hasn't been tampered with?
You verify pipeline output integrity with signed build provenance — cryptographic attestations that state exactly which source commit, build steps, and dependencies produced a given artifact, checked before deployment. The SLSA framework (Supply-chain Levels for Software Artifacts, originated at Google and now under OpenSSF) formalizes this into four levels, and tools like Sigstore's cosign let teams sign container images and binaries for free using short-lived, OIDC-backed certificates rather than long-term private keys. Without this step, a pipeline has no way to distinguish a legitimate build from one where a compromised runner or a malicious action tampered with the output between build and deploy — which is exactly the gap the tj-actions and Codecov incidents both exploited. As of 2024, SLSA adoption is still uneven: a CNCF survey that year found fewer than half of respondent organizations verified build provenance for any of their production artifacts.
How Safeguard Helps
Safeguard closes the gap between finding a pipeline risk and actually fixing it. Our reachability analysis distinguishes vulnerable dependencies that are actually exercised by your code from the noise of transitively-included but unreachable packages, so engineering teams triage the handful of findings that matter instead of every CVE in the tree. Griffin AI correlates those findings with your specific pipeline configuration, repo permissions, and exposure to surface the highest-risk issues first — including secrets, misconfigured tokens, and unpinned third-party actions. Safeguard generates SBOMs automatically on every build and can ingest existing SBOMs from your current toolchain to maintain a continuous, queryable inventory across every pipeline. When a fix is available, Safeguard opens an auto-fix pull request with the patched version and a scoped diff, so remediation ships in the same review flow your team already uses — no separate ticket, no manual backport.