Back to blog

Introducing CI/CD Pipeline Security: the part of your attack surface that ships to production every day

· · 11 min read
Introducing CI/CD Pipeline Security: the part of your attack surface that ships to production every day

We built this because the pipeline is the one piece of infrastructure that touches everything and gets audited by almost no one. Your application code goes through review, static analysis, dependency scanning, and a pentest. The YAML file that builds, signs, and deploys that code usually goes through a pull request nobody reads closely and then runs, with credentials, on every commit for years. That asymmetry is the whole problem, and it is what this module is about.


Why the pipeline is a target, not a utility

For a long time the mental model was that CI/CD is plumbing. It moves code from a commit to a running service, and plumbing is boring, so nobody thought of it as attack surface. That model is wrong, and the last few years have made it expensive to keep believing.

Think about what a pipeline actually holds. It has your cloud deployment credentials, your registry push tokens, your signing keys, your package publishing secrets, and a token that can usually write back to the repository itself. It runs automatically. It runs with more privilege than any single developer. And it very often runs code that came from outside your team: a pull request from a contributor, a third-party action pulled from a public marketplace, a container image referenced by a floating tag.

An attacker who compromises the pipeline does not need to phish an admin or find a memory corruption bug in your product. They inherit the pipeline's privileges directly. They can read every secret the job can see, push a malicious build to your users, or pivot into your cloud account. And because the pipeline is trusted by definition, the malicious activity looks exactly like a normal deploy.

This is not theoretical. The pattern that keeps repeating in real incidents is boringly consistent: a widely used third-party action gets compromised, thousands of pipelines that referenced it by a mutable tag pull the poisoned version on their next run, and secrets start leaving those pipelines in the logs. The root cause is almost never exotic. It is a mutable reference, an over-scoped token, an untrusted input flowing into a shell, a trigger that runs attacker-controlled code with repository secrets. These are misconfigurations, and misconfigurations are findable.


What the module looks for

CI/CD Pipeline Security parses your pipeline definitions the way an attacker reads them: not as build instructions, but as a description of what can run, with what privileges, triggered by whom. The findings fall into a few families that show up regardless of which platform you use.

Mutable and unpinned dependencies

Most pipelines reference external building blocks: a marketplace action, a shared template, a base image, a CLI installed on the fly. When those references point at a moving target (a branch, a floating tag like v1, or latest) you are trusting whoever controls that target to never turn hostile and to never get compromised. History says that trust is misplaced. The module flags every external reference that is not pinned to an immutable identifier and shows you which pipelines inherit the risk, so pinning becomes a mechanical fix instead of a research project.

Untrusted input flowing into execution

The most reliable way to get code execution in a pipeline is to let attacker-controlled text reach a shell or an evaluated expression. A pull request title, a branch name, a commit message, an issue body: on many platforms these are attacker-controlled, and dropping them directly into a run step is a script injection waiting to happen. The module traces where external, untrusted values enter a pipeline and whether they reach a place that executes them, and it distinguishes the triggers that expose secrets to untrusted code from the ones that do not.

Over-privileged tokens and exposed secrets

Pipelines tend to accumulate permissions the way old accounts accumulate access: additively, and never revoked. A job that only needs to read a repo ends up with write. A token scoped to everything sits in a job that runs third-party code. The module surfaces jobs whose privileges exceed what their steps actually require, and it flags secrets that are reachable from steps they have no business touching. Least privilege stops being an aspiration you write in a policy document and becomes a diff you can apply.

Dangerous triggers and runner exposure

Not all pipeline triggers are equal. Some run only your code. Some run code from a fork, with your secrets attached, on a machine you control. The difference between those two is the difference between a safe workflow and a remote code execution primitive, and it is one line of configuration. The module identifies triggers that grant untrusted contributors a privileged execution context and highlights self-hosted runner setups that expand the blast radius when something does go wrong.

Structural misconfigurations across five platforms

GitHub Actions, GitLab CI, Azure Pipelines, Bitbucket Pipelines, and CircleCI all express these ideas differently, but the underlying mistakes rhyme. A permissive default here, a missing approval gate there, a secret that should have been masked and was not. The module normalizes across all five so that a security team running a mixed estate gets one consistent view instead of five dialects to learn.


Where it lives and how it works

You will find CI/CD Pipeline Security in the left navigation under Supply Chain Security, next to Dependency Tracker, SBOM, and Container Images. That placement is deliberate. Your pipeline is part of your supply chain, arguably the most sensitive part, because it is the machine that turns source into the artifact your users actually run. Treating it as a first-class supply chain concern, alongside your dependencies and your SBOM, is the point.

Because Pragma Core is already connected to your repositories, there is nothing new to wire up. The module reads the pipeline definitions that live in those repos and scans them for misconfigurations and insecure workflow patterns. Every result is a check with a stable ID, tied to the exact file it came from, so a finding is never an abstract warning. It is a line you can open and fix.

The workspace view is built for the reality of a large estate. You can search by check, by ID, or by file across all repositories at once, which matters because pipeline misconfigurations are rarely isolated: the same unsafe pattern usually got copy-pasted into a dozen repos, and finding all of them in one query is the difference between fixing a symptom and fixing a habit. From there, three filters narrow the view:

That triage model is the quiet part that makes the module usable. A scanner that only emits open findings becomes noise within two weeks. Being able to separate what is genuinely unhandled from what has been reviewed and accepted is what keeps the list short enough that people keep reading it.

Findings do not sit in isolation either. Because the platform can see your code, your dependencies, and your pipelines together, a pipeline finding can be read in context. An unpinned action is one thing; an unpinned action in a job that also holds your production deploy credentials is another, and Pragma Core can tell the difference.


How this fits the rest of Pragma Core

Pragma Core has always been about the vulnerabilities that live in relationships between things, not in a single bad line. A taint that crosses three functions. A privilege that is fine in one service and dangerous in the one that calls it. CI/CD Pipeline Security is the same idea applied to the build system: the danger is rarely one step, it is how a trigger, an input, a permission, and an external dependency combine.

It closes the loop on Supply Chain Security

Dependency Tracker tells you which third-party packages are vulnerable. SBOM tells you exactly what is in each build. Container Images tells you what ships in your images. CI/CD Pipeline Security tells you whether the machine assembling all of that can be turned against you. Together they cover the supply chain from the packages you pull to the pipeline that ships them.

It uses the same call-graph and context model

The platform already builds an understanding of how your code connects. Extending that to pipelines means a finding is not just "this YAML is risky," it is "this pipeline builds this service, holds these credentials, and is triggered this way." Context is what turns a long list of findings into a short list of things that actually matter.

It is continuous by default

Pipelines drift. A safe workflow gets a new step, a new permission, a new external action, and slowly becomes unsafe again. A one-time audit cannot keep up with that. Because the module re-analyzes on change, the moment a pipeline regresses into a risky state, you know, with the commit that did it.

It speaks all five platforms so your security team does not have to

Real organizations do not run one CI system. They run whatever each team picked, and a security function that wants a complete picture normally has to become fluent in all of them. Normalizing GitHub Actions, GitLab CI, Azure Pipelines, Bitbucket Pipelines, and CircleCI into one model removes that tax: the same check, the same severity, the same triage flow, whichever framework a given repo happens to use. Filter to one framework when you are helping a specific team, or drop the filter and see the whole estate.


What we want you to do with it

If your repositories are already connected to Pragma Core, open Supply Chain Security and look at CI/CD Pipeline Security. The findings are already there. A few concrete things worth doing in the first week:

  1. Sort by severity and start at the top. Ignore the instinct to clear the whole list. The findings that expose credentials or grant untrusted code an execution context are worth more than every low-severity item combined.
  2. Pin your external dependencies. Start with the actions and templates that run in jobs holding real credentials. Immutable references are the single highest-leverage fix in CI security.
  3. Search one check across every repository. When a finding looks like a pattern rather than an accident, search it across all repos. You will usually find the same misconfiguration copy-pasted into a dozen pipelines, and you can fix the whole class in one pass.
  4. Audit your triggers and your token scope. Find every trigger that runs untrusted contributor code with access to secrets, and every job whose privileges exceed what its steps need. Decide deliberately in both cases. Most of the time the answer is to cut.
  5. Acknowledge what you accept, fix the rest. Use the acknowledged state for risks you have reviewed and consciously taken on, so the Active view stays an honest list of what is genuinely unhandled. A queue people trust is a queue people work.

Closing thoughts

The pipeline was never plumbing. It is a privileged, automated, externally-influenced execution environment that ships code to your users, and for years it has been one of the least examined parts of the modern software stack precisely because it was invisible. The attacks that keep landing are not clever. They exploit mutable references, over-scoped tokens, and untrusted input reaching a shell, and every one of those is a misconfiguration you can see and fix once you decide to look.

CI/CD Pipeline Security is how we help you look, continuously, across every CI system your teams actually use, with the context of the code and dependencies those pipelines carry. It is live now under Supply Chain Security for every connected workspace.

Organizations that want to move from "we hope our pipelines are fine" to "we know what runs, with what privileges, triggered by whom" can reach us at pragma-core.com for a demo.


Sources

Related posts
CVE-2026-85978: how one path normalization mismatch turned Akana's admin console into unauthenticated remote code execution
Sep 9, 2026
CVE-2026-78174: how an unredacted session token in a diagnostic log turned a low-privileged WatchGuard Dimension admin into super admin
Sep 1, 2026
Qwen 3.8 27B and the year the open weights caught up: how a 17GB download started beating the frontier
Aug 19, 2026

Start securing your codebase today

Connect your repositories and let AI agents handle continuous scanning, research, and triage.

Have questions? Get in touch →