For years, application security programs have focused on production environments: hardening servers, patching vulnerabilities, deploying WAFs, and monitoring runtime behavior. That focus made sense when most meaningful compromises happened after deployment, by exploiting weaknesses in running applications.
But modern attackers increasingly bypass production defenses. Instead of attacking the application at runtime, they compromise the systems that build, package, and deliver software: CI/CD pipelines and the software supply chain behind them.
In many organizations, CI/CD pipelines are now a more valuable and more fragile target than production itself. The reason is simple: pipelines sit at the intersection of trust, privileges, and distribution. If attackers can control the pipeline, they can control what reaches production—and what reaches users.
This article explains why pipelines became a primary attack surface, what recent supply chain incidents teach us, how pipeline security differs from runtime security, and what common design mistakes keep pipelines vulnerable. The conclusion is clear: the pipeline is a trust boundary, and it must be engineered as such.
The evolution of software attacks
Classic application security threats targeted runtime vulnerabilities: SQL injection, RCE, SSRF, auth bypass, and privilege escalation. Defenders have spent two decades raising the cost of these attacks through:
- Improved patching, dependency scanning, and vulnerability management
- Cloud-native security controls and managed infrastructure
- Better isolation (containers, sandboxes, segmentation)
- Centralized logging and detection capabilities
As a result, adversaries adapted. If production becomes harder to exploit directly, attackers look for leverage elsewhere—and the software delivery process offers that leverage.
Instead of asking “How do I break into this running system?”, attackers increasingly ask:
How do I get my code shipped as if it were legitimate?
When that happens, defenses designed for runtime compromise can become irrelevant. A malicious update delivered through legitimate channels is not a “breach” in the traditional sense— it can look like business as usual.
Three incidents that illustrate the shift
High-profile supply chain incidents did not happen because runtime defenses were weak. They happened because attackers compromised delivery mechanisms that sit upstream of production. The details differ, but the pattern is consistent: compromise a trusted build or distribution step, and you inherit trust at scale.
SolarWinds: compromise the build and reach everyone
In the SolarWinds incident, attackers were able to inject malicious code into software updates. The defining characteristic was not a single exploited server—it was the ability to distribute backdoored software through a trusted update channel.
The attacker’s ROI was massive: compromise the build or release pipeline once, then let customers install your payload for you.
Codecov: compromise the CI tooling and steal secrets at scale
In the Codecov incident, a compromise affected how CI environments handled a script. The practical impact: CI systems running in many organizations leaked sensitive information.
CI environments are extremely sensitive because they commonly hold:
- Repository tokens
- Cloud credentials
- Signing keys or access to signing services
- Deployment secrets
This incident highlights that CI tooling is not “just automation”—it’s a high-value secrets processing system.
3CX: compromise a vendor and weaponize trust
The 3CX incident demonstrated another supply chain dynamic: compromise a vendor and weaponize trust to distribute malicious software to downstream customers.
From a defense standpoint, the lesson is not limited to vendors. Internally, your CI/CD pipeline is effectively a “vendor” to your production environment and to your users: production trusts the pipeline’s outputs.
Why the pipeline is more attractive than production
Attackers choose targets based on leverage. CI/CD pipelines offer leverage that production systems rarely match.
1) Pipelines aggregate trust
A pipeline is the connective tissue between:
- Source code repositories (Git)
- Dependency registries (npm, PyPI, Maven, etc.)
- Build systems and runners
- Artifact repositories (container registries, package repos)
- Signing systems and provenance metadata
- Deployment targets (Kubernetes, cloud accounts, production servers)
Compromising production usually gives you access to one environment. Compromising the pipeline can give you:
- Access to multiple environments via automation credentials
- Control over release artifacts
- Influence over what gets deployed and when
Pipelines are “trust multipliers”: they can take untrusted inputs and produce trusted outputs. If attackers control that transformation, they control trust.
2) Pipelines operate with high privileges by design
Automation needs privileges. Pipelines often require permissions to:
- Read and write repositories (including tags and releases)
- Pull dependencies and publish artifacts
- Access secrets for signing or deployment
- Deploy into staging or production
In many organizations, pipeline identities become “super identities” over time, because it’s easier to grant broad access than to engineer fine-grained permissions.
This creates a predictable attacker strategy: compromise the pipeline identity instead of fighting production defenses.
3) Pipeline compromise scales better
Runtime compromise often scales poorly: you must repeatedly exploit targets, handle variability across environments, and maintain persistence per target.
Pipeline compromise scales efficiently: inject once, distribute everywhere. If you can modify a build step, a dependency resolution path, or a release artifact, you can compromise many systems while appearing legitimate.
4) Detection is harder because “everything looks normal”
Production security tools look for suspicious runtime behavior: unexpected network calls, privilege escalations, abnormal processes. But if malicious code ships as a normal release, it executes as part of the application’s expected behavior.
Without strong integrity controls and provenance, defenders may struggle to answer:
Is this binary/container actually what we intended to build?
Pipeline security vs runtime security
A common misconception is that pipeline security is just “runtime security earlier in the lifecycle.” That framing is incomplete. Pipeline security and runtime security protect different guarantees.
Runtime security answers:
What is this system doing right now, and is it malicious?
Pipeline security answers:
Why should we trust this software at all?
If the pipeline is compromised, runtime defenses might faithfully protect a malicious application, because from the system’s perspective it is “the application.” The real failure happened upstream, at the point where trust was established.
This is why supply chain security focuses on:
- Integrity of build outputs
- Provenance (who/what built it, where, and how)
- Verification gates before deployment
- Reducing the ability to tamper with build and release steps
Where pipelines are actually vulnerable
To secure pipelines, we must be specific about where attacks happen. “CI/CD” is not a single component. It’s a chain of components and trust transitions. Here are the most common attackable points.
Source: pull requests and untrusted contributions
Many pipelines execute code from pull requests. If the pipeline treats PR code as trusted (or leaks secrets to PR builds), attackers can exfiltrate credentials or modify build outputs.
Dependencies: transitive trust at internet scale
Modern builds pull hundreds or thousands of third-party dependencies. A compromised dependency, a typosquatting package, or dependency confusion can shift execution inside the build environment—often without touching your source code.
Pipeline configuration: “code” that is often reviewed less
CI definitions (YAML workflows, shared templates, reusable actions) control execution. A subtle change can:
- Expand permissions
- Introduce data exfiltration
- Switch artifact sources
- Disable security checks
Yet CI configuration sometimes receives less rigorous review than application code.
Runners: the execution environment is a security boundary
Hosted runners, self-hosted runners, and ephemeral containers all have different risk profiles. But the key point is universal: runners execute untrusted inputs. If runners are not isolated properly, they become an attacker’s foothold.
Artifacts: integrity and provenance are often assumed, not proven
Many organizations assume that “if it came from CI, it is safe.” That is precisely the assumption attackers exploit. Without signatures, attestations, and verification gates, artifact integrity is fragile.
Common pipeline design mistakes
Most pipeline compromises succeed because of predictable engineering mistakes—usually driven by speed, convenience, or unclear ownership. These mistakes create silent trust violations.
Mistake #1: Treating CI runners as “internal and trusted”
Runners often run within trusted networks and have access to sensitive resources. But they execute code that may be influenced by external contributors, dependencies, or third-party actions. If the runner is compromised, the attacker can:
- Steal secrets from environment variables
- Extract tokens from local config
- Modify build outputs
- Persist via caches, images, or shared volumes
Mistake #2: Over-privileged pipeline identities
Broad tokens (e.g., “write-all” repository tokens, multi-environment cloud credentials) are common. They make automation easier—but they also give attackers a fast path to impact.
Mistake #3: Weak boundaries between pipeline stages
If an early stage can influence artifacts used by later stages without integrity verification, artifact poisoning becomes trivial. This includes:
- Unverified build caches
- Shared workspaces across jobs
- Artifacts passed between stages without checks
Mistake #4: Uncontrolled third-party components
Reusable actions, plugins, and templates are powerful. But they also add supply chain risk inside CI itself. If third-party components are not pinned, reviewed, and constrained, they become an execution vector.
Mistake #5: “Security checks” that do not gate deployment
Security scanning that does not block releases is often treated as “good enough.” From an attacker’s perspective, it is irrelevant. Controls must be enforceable: they must affect what can be built, signed, and deployed.
The pipeline is a trust boundary
The right mental model is not “CI/CD as automation.” It is CI/CD as a trust boundary.
A trust boundary is where untrusted inputs become trusted outputs. That is exactly what a pipeline does:
- It takes source code (potentially influenced by many actors)
- It resolves dependencies (often from external ecosystems)
- It executes build instructions
- It produces artifacts that production will trust
If you do not make trust explicit, you get implicit trust. Implicit trust is what attackers monetize.
Engineering the pipeline as a trust boundary means:
- Explicit stage boundaries with isolation and verification between them
- Least privilege for pipeline identities, per job and per environment
- Ephemeral execution (or strong isolation) for runners and builds
- Cryptographic integrity for artifacts (signing and verification)
- Provenance and attestations that can be validated at deployment time
What a modern security strategy should include
If pipelines are primary attack surfaces, security programs must invest accordingly. Not by adding more “checks,” but by building strong guarantees into the delivery process.
1) Threat model the pipeline (not just the application)
Map trust boundaries: PR inputs, dependency resolution, runners, artifact storage, signing, and deployment. Identify where untrusted influence can enter.
2) Reduce privilege and scope aggressively
Use job-scoped identities, environment-scoped credentials, short-lived tokens, and explicit permission boundaries. Avoid “pipeline superusers.”
3) Harden runners and execution environments
Prefer ephemeral runners where possible. If using self-hosted runners, isolate them: network restrictions, filesystem controls, no shared long-lived state, and strict segregation between untrusted and trusted workloads.
4) Make integrity verifiable, not assumed
Sign artifacts, generate attestations, and verify them before deployment. Ensure that production trusts verification, not merely the fact that “CI produced it.”
5) Validate pipeline changes like production changes
Treat CI configuration as high-risk code. Use code owners, reviews, and policy enforcement to prevent silent privilege expansion or injection of untrusted steps.
Conclusion
CI/CD pipelines have quietly become some of the most critical—and most exploited—components in modern software ecosystems. They aggregate trust, operate with high privileges, and provide attackers with a high-leverage path to impact at scale.
The most important step is to shift the mental model:
A CI/CD pipeline is not “just automation.” It is a trust boundary.
Organizations that engineer pipelines with explicit trust boundaries—through isolation, least privilege, integrity, and provenance—will be in a far better position to defend against the next generation of software supply chain attacks.