Executive Summary
- CI/CD pipelines are production infrastructure, and attackers treat them that way. The pipeline is a high-trust, high-velocity path from a developer's keyboard to production, and it holds the credentials, signing keys, and deploy permissions an attacker wants. A single unreviewed change, or one stolen token, can travel that path in minutes.
- The dominant risks are already cataloged. The OWASP Top 10 CI/CD Security Risks, first published in 2022, remains the reference map and is the backbone of this article. Three of its ten entries are about identity and credentials, and the class most often exploited in practice is Poisoned Pipeline Execution, where unreviewed code runs inside the build with all of the build's privileges.
- Real incidents follow a small number of repeatable paths. The SolarWinds build-system implant, the Codecov secret exfiltration, dependency confusion, and the 2025 compromise of the tj-actions/changed-files GitHub Action (CVE-2025-30066) are variations on the same moves: get a foothold, execute in the pipeline, harvest secrets, move laterally, and tamper with what ships.
- Professnet treats pipeline security as an operational discipline, not a scanner rollout. We map the attack paths that actually apply to your stack, lock down flow control and pipeline permissions, pin and verify what your builds consume, and wire pipeline telemetry into the SOC so an anomaly in a build is an alert rather than a footnote discovered months later. The ZEUS Security360 platform folds CI/CD and infrastructure-as-code posture into that practice.
Why Is the Pipeline Such a Target?
For most of the last decade, security testing lived at the edges: a firewall in front of production, a scanner behind it. The pipeline in between was treated as plumbing. That assumption no longer holds. A modern CI/CD system takes code from a developer's machine to production in minutes, often with full automation and minimal human involvement, and to do that it is granted exactly the things an attacker needs: read and write access to source, the secrets that builds consume, signing material, and the credentials that push to cloud accounts and registries.
The result is a high-value target with a large and diverse surface. A single pipeline usually spans a source-control system, one or more CI runners, an artifact registry, a deployment system, and a container or Kubernetes platform, plus a long tail of third-party actions, plugins, and dependencies, each added with a line or two of configuration. OWASP puts it plainly in the Top 10 CI/CD Security Risks: CI/CD environments are the beating heart of a software organization, and adversaries of every level of sophistication have shifted attention to them because they are an efficient path to an organization's crown jewels.
The mental model that helps most is simple. Treat the pipeline as production infrastructure and give it the same rigor you give production servers: least privilege, strong identity, verified inputs, and real logging. Everything below follows that.
In Plain Language
- CI/CD pipeline: the automated sequence that builds, tests, and ships code. Continuous Integration is the build-and-test half; Continuous Delivery or Deployment is the release half.
- SCM: the source-control management system, such as a Git host, where code lives and changes are reviewed and merged.
- Runner (or agent): the machine, often ephemeral, that executes the steps of a pipeline job.
- Artifact: the thing a build produces and later deploys, such as a container image, a package, or a binary.
- Secret: a credential a pipeline uses, such as an API key, a cloud token, or a signing key.
- Poisoned Pipeline Execution (PPE): getting your own commands to run inside someone else's build, with the build's privileges, usually by editing the pipeline definition or a file it runs.
The Ten Risks, Grouped by What They Break
The OWASP Top 10 CI/CD Security Risks (CICD-SEC-1 through CICD-SEC-10) is the most useful catalog of where pipelines go wrong. It is worth reading in full, but for navigating attack paths it helps to group the ten into four themes.
- Flow and execution (SEC-1, SEC-4, SEC-7). Weaknesses in how code and commands are allowed to run: missing review and approval gates, the ability to inject build commands, and insecure platform configuration. This is where an attacker gets code executing where it should not.
- Identity and access (SEC-2, SEC-5, SEC-6). The credentials and permissions layer: sprawling or stale accounts, pipelines that run with far more access than they need, and secrets that are long-lived, shared, or sitting in the wrong place. Three of the ten risks live here, which is why identity is often called the real perimeter of a pipeline.
- Supply chain and integrity (SEC-3, SEC-8, SEC-9). What the build trusts and consumes: external dependencies, third-party services and actions, and artifacts that are never verified. This is the path that turns one upstream compromise into thousands of downstream ones.
- Visibility (SEC-10). Whether you can see any of the above happening. Engineering systems are frequently outside the reach of the logging and monitoring that covers the rest of the estate, and without that visibility every other risk is harder to detect and slower to answer.
How Do Attackers Actually Move? Five Common Paths
Individual risks are useful for auditing. Attacks, though, are chains: an intruder rarely needs just one weakness, and a single control in the right place can break the whole sequence. Five paths cover the large majority of real CI/CD incidents.
Path 1: The unreviewed change (SEC-1)
The most direct path skips review entirely. If a deployable branch does not require approval, or required reviews can be bypassed, then anyone who can write to source, whether an outside attacker with a stolen credential or a malicious insider, can push a change that flows to production without a second set of eyes. Researchers have repeatedly shown ways to defeat weakly configured branch protection, including techniques that abuse the CI system itself to approve or merge changes. The fix is unglamorous and effective: require review by someone other than the author on anything that can reach production, and remove the shortcuts.
Path 2: Poisoned pipeline execution (SEC-4)
The most commonly exploited class of CI/CD attack does not touch production directly. Instead, the attacker gets their commands to run inside the build. In direct PPE, they modify the pipeline definition itself, often in a pull request from a fork, so that a new step runs whatever they choose. In indirect PPE, they modify something the pipeline already runs, a test script, a build file, or a linter configuration, and let the existing pipeline execute it for them. Either way the payload runs on the runner with the job's identity and access. From there the attacker has whatever the build has: its secrets, its tokens, and its network reach. This is the hinge that most of the other paths swing on.
Path 3: The compromised dependency or action (SEC-3, SEC-8, SEC-9)
Modern builds pull in a great deal of code they did not write and do not control: open-source packages, base images, and reusable CI actions or plugins. Each is a place to hide. Attackers publish malicious packages, typosquat popular names, or exploit dependency confusion, where a public package shadows a private one of the same name and gets pulled into the build by mistake. They also target the shared third-party building blocks of the pipeline itself. When a widely used action or plugin is compromised, every pipeline that trusts it inherits the problem at once. The tj-actions incident below is a clean example of this path.
Path 4: Secret harvest and lateral movement (SEC-6, SEC-5, SEC-2)
Once code is running in the build, through Path 2 or Path 3, the next move is to collect credentials and pivot. Pipelines are full of them: secrets injected as environment variables, tokens mounted into the job, and cloud credentials the build uses to deploy. An attacker running in that context can read environment variables, scrape files, or even dump the runner's process memory to recover secrets that were meant to stay masked. If the pipeline's permissions are broad, or its cloud trust is over-scoped, those harvested credentials open the door to cloud accounts, registries, and other systems. The Codecov breach is the archetype: a modification to a build-time script quietly exfiltrated environment-variable secrets from thousands of pipelines.
Path 5: Tampered artifact to production (SEC-9, SEC-1)
The most patient path leaves the source code alone and attacks what the build produces. If artifacts are not signed and verified, an attacker who can influence the build, or the registry, can substitute or modify the artifact so that something malicious flows downstream wearing the pipeline's trust. SolarWinds is the defining example: the implant was placed inside the build process, so the resulting binary was validly signed and looked legitimate all the way to eighteen thousand customers. Without provenance and signature verification, this path is very hard to see.
A Recent Path, Start to Finish: tj-actions/changed-files
In March 2025, a single compromised GitHub Action turned Paths 3 and 4 into a live, large-scale incident. The action, tj-actions/changed-files, is used to work out which files changed in a pull request or commit, and it was present in more than twenty-three thousand repositories. The compromise was assigned to CVE-2025-30066, with a CVSS score of 8.6, and it is worth walking through because it shows how ordinary the moves are.
The likely starting point was upstream. Investigators found that a related action, reviewdog/action-setup, had been compromised around the same time, tracked as CVE-2025-30154, and that this may have leaked a token used in the tj-actions project. With that foothold, the attacker gained a personal access token belonging to a bot the maintainer used, then modified the action's code and retroactively moved its version tags so they all pointed at a single malicious commit. Anyone referencing the action by tag now pulled the attacker's code.
What the code did is the instructive part. On each run it downloaded and executed a script that read the runner's process memory, located the decrypted secrets, and printed them, double base64 encoded, into the build logs. On a public repository those logs are public by design, so the exposed secrets, which could include cloud access keys, GitHub tokens, npm tokens, and private keys, were readable by anyone. Private repositories were at lower risk, because an outsider cannot read their logs, though anyone with log access should still treat those secrets as exposed.
Two details matter for defense. First, the attack was caught by anomaly detection rather than by a static signature: monitoring flagged an unexpected outbound network call to a code-sharing gist, which is what a build step reaching out to fetch a payload looks like. Second, repositories that had pinned the action to a specific commit digest, rather than a moving tag, were not affected, because the moved tags never changed the commit those pipelines resolved to. The United States Cybersecurity and Infrastructure Security Agency issued an advisory covering both CVEs, and the maintainers cleaned the tags and added protections.
Which Controls Break Which Path?
The encouraging part of thinking in paths is that the controls are well understood, and each one interrupts a specific move. None of them is sufficient alone; layered, they make every path much harder to complete.
- Enforce flow control. Require review by a second person on anything that can reach production, disable direct pushes and automatic merges to deployable branches, and put approvals and protected environments in front of deployments. This closes Path 1 and raises the bar for Path 5. Controlling who can change production, and when, is a natural complement, which is why we pair pipeline controls with just-in-time access, as described in our note on Microsoft Entra PIM for just-in-time access.
- Contain pipeline execution. Assume some pull requests are hostile. Run untrusted code on isolated, ephemeral runners that hold no secrets, and keep the jobs that build untrusted code separate from the jobs that hold credentials. This is the single most valuable control against Path 2, the poisoned pipeline.
- Verify what you consume. Pin third-party actions and critical dependencies to immutable commit digests rather than mutable tags, maintain an allow-list of permitted actions, pull dependencies through vetted internal proxies, verify checksums, and generate a software bill of materials for every build. This is the direct counter to Path 3, and it is exactly what would have blunted the tj-actions compromise.
- Cut standing credentials. Move from long-lived stored secrets to short-lived, workload-scoped credentials, using cloud OIDC federation where you can, so a leaked value expires quickly and cannot be replayed. Scope pipeline tokens to the least privilege the job needs and never share credentials across contexts. This limits the blast radius of Path 4.
- Prove integrity. Sign commits and artifacts, using tooling such as Sigstore and in-toto, adopt SLSA provenance, so you have a verifiable record of how each artifact was built, and verify those signatures before anything deploys. This makes Path 5 visible instead of silent. Our companion article on building DevSecOps gates into your pipeline covers SBOMs, signing, and SLSA levels in more depth.
- See all of it. Treat the pipeline and the source-control system as first-class log sources. Ship their audit and activity logs to your SIEM, and alert on the high-signal events: changes to workflow files, new third-party app or OAuth installations, edits to branch protection, unusual outbound network calls from runners, and permission changes. This is the answer to the SEC-10 blind spot, and it is where a managed detection capability earns its keep. The ZEUS Security360 platform brings pipeline and infrastructure-as-code posture into the same operational view, and our Managed SOC watches the resulting telemetry, so an anomaly in a build becomes an alert.
Where Should You Start?
You do not need every control on the first day, and trying to boil the ocean is how these programs stall. A pragmatic sequence closes the most-exploited paths first, at the lowest cost, and builds from there.
- Find the one pipeline that can reach production secrets from a pull request, and fix that first. It is the highest-value target and usually the fastest thing to contain. Inventory the rest as you go.
- Pin third-party actions and critical dependencies to immutable digests and turn on an allow-list. This closes the path the tj-actions incident used, and it is a configuration change, not a project.
- Lock flow control on deployable branches: required reviews by a second person, no direct pushes, no auto-merge, and protected deployment environments.
- Cut standing credentials. Move builds to short-lived OIDC credentials, and scope pipeline tokens to least privilege. This shrinks the blast radius of anything that does get in.
- Centralize logging and prove integrity. Ship pipeline and source-control logs to your SIEM and alert on the high-signal events, then add artifact signing and provenance and ratchet toward higher SLSA levels over time.
The pattern is the one we apply to detection and to shift-left gates alike: start narrow and high-signal, close the paths that are both most exploited and cheapest to close, prove the value, and expand. The hard part is never turning on a single control. It is the judgment about which paths matter for your stack, and the operational discipline to keep the controls trustworthy as the pipeline changes.
Hardening a pipeline, or think one has already been used against you? We can help you map the real attack paths, close them in priority order, and put the pipeline under the same monitoring as the rest of your production estate. To discuss a CI/CD security assessment, talk to Professnet, or explore how we approach security as an operational discipline.
