All articles

CI/CD security: A practical guide to trusted pipelines

DevSecOpsSoftware Supply Chain
Key Takeaways
  • CI/CD security has four layers: source verification, signed SBOMs/provenance, access controls, and continuous workflow scanning.

  • Recent incidents (TanStack, AntV, tj-actions) show attackers exploit tag hijacking, dependency confusion, and secret exfiltration.

  • Chainguard Actions and Libraries centralize supply chain controls, replacing manual per-workflow checks with secure-by-default sources.

The attack patterns in CI/CD security are well-known, as are the defenses. Yet pipelines keep getting compromised because many teams fail to implement controls that comprehensively guard against attacks.

Consider the July 2026 AsyncAPI compromise, where a misconfigured GitHub Actions workflow executed code from an untrusted pull request and exposed a privileged bot credential. Attackers used that access to alter release branches, after which the project’s legitimate OIDC publishing workflow automatically distributed poisoned npm packages with valid provenance signatures.

CI/CD security helps prevent attacks like the AsyncAPI compromise by verifying what a pipeline runs, limiting what each job can access, and recording how each artifact was built.

The controls fall into four layers: source verification, signed SBOMs and provenance, pipeline access controls, and continuous workflow scanning.

What is CI/CD security?

CI/CD security protects continuous integration and continuous delivery pipelines from unauthorized code execution, dependency substitution, credential exposure, and artifact tampering. Continuous integration pulls changes into a shared build and test path, while continuous delivery prepares those changes for release. In many organizations, continuous deployment extends the same path into production.

CI/CD security encompasses the entire pipeline, including source control, workflow definitions, build runners, package registries, third-party actions, secrets, artifact storage, deployment identities, and metadata associated with the software produced. CI/CD security asks whether the pipeline ran the code you intended, used the dependency source you approved, and produced an artifact whose origin can be verified.

CI/CD security has four trust surfaces:

  • Code and dependency inputs: repositories, package registries, third-party actions, reusable workflows, build scripts, base images, and build tools.

  • Execution environment and authority: runners, tokens, secrets, signing keys, deployment identities, network access, and environment approvals.

  • Release artifacts and evidence: artifact storage, SBOMs, provenance attestations, signatures, and build records.

  • Policy and change controls: workflow triggers, permissions, protected workflow paths, registry settings, and the review rules governing changes to them.

Because pipelines act on their inputs automatically, a workflow reference, package name, build script, or pull request trigger works as an instruction to execute code under a particular identity, rather than passive configuration. If you treat those instructions as part of the software supply chain, the control model becomes clearer.

Here is a practical test for determining your level of security: for every pipeline that can touch production, try to name the sources it trusts, the credentials it receives, the workflow changes that require review, and the evidence proving the final artifact came from the expected source. If that answer depends on a person reading a YAML file perfectly every time, the controls are weak.

Why CI/CD pipelines are high-value targets

Most production security failures begin after code is deployed, when an attacker exploits a running service. CI/CD pipelines pose a different risk. They are designed to fetch and execute changing code, then give that code authority to publish artifacts, sign releases, or deploy to production. A mutable action tag, compromised dependency, or unsafe pull request trigger can, therefore, turn a routine input change into privileged code execution. The result can be a malicious build or release that downstream users trust.

The OWASP Top 10 CI/CD Security Risks spans everything from dependency chain abuse to credential hygiene and pipeline access controls, but the common thread is simple. Automation turns small trust mistakes into compromised builds, tampered artifacts, or unsafe deployments.

These failures start with routine workflow and dependency configurations that control what runs in CI and what credentials they get, for example:

  • A workflow references third-party actions by tag instead of pinning to an immutable commit SHA.

  • A build resolves dependencies from the wrong registry or namespace because the pipeline doesn’t enforce trusted sources.

  • A PR-triggered job executes code from a fork or unreviewed branch with permissions intended for trusted builds.

  • A long-lived cloud key or deploy token is injected into the job environment, expanding the blast radius if any step is compromised.

Each decision has a safeguard, but that safeguard has to match the path. Pinning an action does not fix broad GITHUB_TOKEN permissions, secrets redaction does not prove artifact origin, and an SBOM does not stop a privileged workflow from running unreviewed code. CI/CD security works best when the layers are mapped to the failure modes they interrupt.

Four attack paths to map

The dominant CI/CD attack patterns follow the pipeline: source execution, dependency resolution, workflow logic, and secrets reachable once execution starts.

Attack pattern

Where it enters

What the attacker wants

Defense layer that interrupts it

Tag hijacking

Mutable action or workflow references

Run new code behind a trusted version label

Source verification and immutable references

Dependency confusion

Package resolution in the build

Pull attacker-controlled code from the wrong registry or namespace

Trusted package sources and registry boundaries

Poisoned pipeline execution

Workflow files, build scripts, and trigger behavior

Turn normal automation into privileged code execution

Pipeline access controls and protected workflow changes

Secret exfiltration

Job environment, runner memory, logs, and outbound calls

Capture tokens, signing keys, or cloud credentials

Least privilege, short-lived credentials, and workflow scanning

Recent open source malware incidents illustrate each path, and what to look for in your own workflows:

  • On March 14, 2025, attackers retroactively modified tj-actions/changed-files version tags and affected more than 23,000 repositories.

  • On May 11, 2026, in connection with the Mini Shai-Hulud campaign, attackers exploited a pull_request_target misconfiguration to hijack TanStack's legitimate CI/CD pipeline, publishing 84 malicious versions across 42 @tanstack npm packages. The attackers extracted an OpenID Connect (OIDC) token directly from GitHub Actions runner memory to authenticate the malicious releases, bypassing the pipeline's own publish step.

  • On May 19, 2026, the AntV compromise (also tied to Mini Shai-Hulud) published 639 malicious versions across 323 packages, with a payload that harvested more than 20 types of credentials — including cloud provider keys, npm and GitHub tokens, SSH keys, Kubernetes and Vault secrets, and database connection strings — and attempted Docker container escapes. Unlike the TanStack incident, the AntV attack entered through a compromised npm maintainer account rather than a workflow misconfiguration, demonstrating that secret exfiltration can follow either path.

In every case, attackers abused the structural trust model of public registries and workflows.

Dependency chain abuse is the package-side version of the problem. The build environment fetches and executes code from dependency managers or package managers, and a bad resolution decision results in code execution. Poisoned pipeline execution is the workflow-side version. A user who can influence pipeline configuration or files consumed by the pipeline inserts malicious commands into the build path.

Secret exfiltration happens once an attacker gets code running in the job. As soon as a compromised action, dependency, or workflow step executes, it can read whatever the pipeline exposes.

Verify source before execution

A workflow can run different code even when its configuration has not changed. An action tag such as @v3 can be repointed to a new commit by its publisher. Pin third-party actions to full commit SHAs, which lock each reference to one specific version. GitHub recommends this approach.

SHA pinning is not the entire control, though. The SHA still has to belong to the expected repository, the source has to match the project you meant to consume, and the organization needs a way to notice when a workflow drifts back to tags or branches. Mature teams usually combine several checks:

  • Require full-length SHAs for third-party actions and reusable workflows.

  • Allowlist approved action publishers or internal mirrors where the platform supports it.

  • Review changes under .github/workflows/, .gitlab-ci.yml, Jenkinsfiles, and similar pipeline entry points with CODEOWNERS or equivalent ownership controls.

  • Restrict package manager resolution to approved registries and namespaces.

  • Lock package versions and review registry configuration changes as code changes, not local developer preferences.

Dependency confusion is the same source-verification problem in package form. If the build can reach both an internal registry and a public registry, a package name collision or namespace mistake can route installation to code the organization never approved. Scanning the package later is useful, but the stronger fix is to configure the build to install each dependency from one approved source, with explicit package scopes, locked versions, and packages reviewed before the build uses them. That control works best when teams point their package managers at an approved source that enforces registry and namespace rules, serves locked versions, and provides verifiable build evidence where available.

Attest what pipelines produce

Signed SBOMs and provenance attestations give auditors and incident responders the evidence they need after the build. In GitHub Actions, teams can generate this evidence with artifact attestations. An SBOM lists the components in the artifact. Provenance describes the source, builder, workflow, and build inputs that led to the artifact. Together, those records make the audit path machine-checkable:

  • The source that produced the artifact.

  • The build system that produced the artifact.

  • The workflow and inputs used.

  • The components included in the artifact.

This layer supplements source verification by proving that the resulting artifact traces back to the expected source.

Attestations also change incident response. Beyond providing a compliance record, they help teams determine whether an artifact changed after the build and make the chain reviewable without forcing a responder to reverse-engineer it later. When a package, action, or workflow is suspected of being compromised, a team with signed provenance can query which artifacts were produced by the affected input and which deployments consumed them. Without provenance, the same investigation requires digging through logs, timestamps, package caches, and runner records, then making best guesses about which build was really live.

Keep permissions job-sized

Pipeline access controls decide how much damage a bad step can do. If a workflow receives write access to the repository, production deployment rights, and long-lived cloud credentials by default, then tag hijacking and poisoned pipeline execution become higher-impact events.

GitHub's secure use reference recommends setting the default GITHUB_TOKEN permission to read-only and increasing permissions only where an individual job needs them. Across CI/CD systems, permissions should be granted at the smallest practical scope, assigned only to the jobs that need them, and kept active for the shortest practical time. Broad workflow-level permissions are easy to write. They also make every step in the workflow part of the blast radius.

Several controls reinforce that boundary:

  • Use job-level permissions instead of broad workflow defaults.

  • Keep secrets out of workflows triggered by untrusted code.

  • Protect deployment environments with required reviewers.

  • Use OIDC for short-lived cloud credentials instead of storing long-lived deploy secrets.

  • Separate build, test, signing, and deployment identities.

  • Require review for workflow file changes, not only application code changes.

GitHub Actions’ pull_request_target trigger runs in the context of the base repository. That lets maintainers label, comment on, and otherwise automate pull request workflows. Trouble starts when a pull_request_target workflow checks out and executes code from an untrusted pull request. That code can then run with permissions or access to secrets intended for trusted workflows. The fix is to separate trusted metadata handling from untrusted code execution, keeping secrets away from jobs that process unreviewed changes, without banning the automation that makes the trigger useful.

Secret exfiltration follows the same logic. Masking helps, but redaction is not guaranteed for every transformed value or log path. A pipeline that uses OIDC, job-sized permissions, environment approvals, and short-lived tokens gives a compromised step less to steal. Log redaction only protects secrets that appear in logs. If every job receives the same deploy secret, any compromised step can exfiltrate or use it before redaction has any effect.

Scan workflow configuration continuously

Workflow configuration changes faster than most security reviews. A new uses: line, a permission block copied from another repository, a trigger added for convenience, or a package registry override can change what the pipeline runs and what it is allowed to access without changing application code at all. Continuous scanning keeps those changes visible after the first hardening pass is over.

Configuration scans should flag:

  • Unpinned actions and reusable workflows.

  • Write-scoped tokens where read-only access would work.

  • Trigger combinations that expose secrets to untrusted code.

  • Registry, package, or dependency update settings that changed without review.

GitHub's secure use reference points teams toward code scanning for vulnerable GitHub Actions workflow patterns and toward OpenSSF Scorecards for checks that include script injection, token permissions, and pinned actions. Scorecards are not a complete CI/CD security program, but they make drift harder to miss. The moment a workflow changes from a pinned action to a tag, expands token permissions, or introduces a dangerous trigger pattern, the finding belongs in the same review loop as a failing test.

Platform teams should review changes to actions, permissions, triggers, and registry endpoints against the last known-good workflow, rather than relying on raw scanning coverage. A new privileged trigger, third-party action, or registry endpoint deserves the same review as a new production deployment path.

How we help

The four attack paths above involve the actions and packages a pipeline fetches, along with the evidence attached to its output. Chainguard Actions and Chainguard Libraries help teams secure those inputs and verify what their pipelines produce.

Chainguard Actions and Chainguard Libraries move high-risk trust decisions out of scattered workflow files and into centrally governed sources. This reduces the number of places where each team must manually recreate supply chain controls.

Chainguard Actions makes GitHub Actions secure-by-default. Every upstream action in the Chainguard Actions catalog is continuously scanned for vulnerabilities around the clock. When a vulnerability is detected in a new release, it's removed, and then the new version is published to the catalog. It was built to address the same attack classes covered above, including tag hijacking, dependency confusion, pull_request_target abuse, and secret exfiltration through logs, while fitting into the workflows teams already run. Migrating to Chainguard Actions requires updating the uses: line in your workflow files to reference the Chainguard-hardened action. To automate this process across all your repos, install the Guardener GitHub app. Today, Chainguard Actions hardens GitHub Actions with coverage for GitLab CI/CD, Azure Pipelines, Jenkins, and CircleCI in development.

Chainguard Libraries addresses the same CI/CD security challenges for language dependencies. Teams replace live reliance on npm, PyPI, and Maven Central with a trusted source for Java, Python, and JavaScript packages. Chainguard builds the newest and most popular Python and Java (starting with SpringBoot and log4j) packages from source in a SLSA Level 3 environment, which eliminates more than 98% of malware in the ecosystems it covers because malware has no verifiable source. For packages Chainguard has not built yet, Chainguard Repository provides a policy-controlled upstream fallback. Repository serves those packages from the upstream registry, but holds newly published versions for a default cooldown window before making them available. That delay creates time to identify and stop malicious releases before they reach downstream builds. Before any package is served, Chainguard scans it for malware and greyware, including sandboxed execution to observe its behavior.

Instead of asking every workflow author to remember every supply chain control, the organization can make safer inputs easier to consume, make privileged jobs harder to create accidentally, and make drift visible when the pipeline changes.

Find the weak points in your pipeline

Open one production workflow and check:

  • Whether all third-party actions are pinned to immutable references or replaced with verified-source equivalents.

  • Whether untrusted code can reach secrets, write-scoped tokens, or deployment credentials.

  • Whether every release artifact carries a signed SBOM and provenance attestation.

  • Whether workflow scanning runs after configuration changes, or only after someone remembers to check.

Those answers reveal where pipeline security still depends on manual checks instead of enforced controls. Prioritize the gaps you find in workflows with the highest blast radius, especially workflows that deploy, sign releases, or access production secrets. Repeat the same review across the action catalog, package sources, artifact evidence, and workflow scanners. CI/CD security gets easier when the safest path is the default path, and when every exception is visible enough to review before the pipeline runs.

Share this article
Execute commandCG System prompt

$ chainguard learn --more

Contact us