Insufficient Pipeline-Based Access Controls
A pipeline step runs with far more access than its job requires, so any code that reaches it inherits the surplus.
If this is new to you
Build machines tend to be provisioned once, with whatever permissions any job might conceivably need, and then every job inherits all of it. So the step that compiles your TypeScript is running with credentials that can reach your production database, because some other step needed them once.
That matters because a build is untrusted code execution by design — it runs whatever is in the repository, plus whatever your dependencies do during installation. The gap between "the build ran" and "an attacker ran" is not a technical boundary. It is a hope.
What to do about it
Ask a blunt question about each step: if this step wanted to, what could it do? Write down the credentials and the network reach it actually has, then compare that to what it legitimately needs. The gap is your finding.
Scope secrets to the step that needs them rather than injecting them into the whole pipeline. Most CI systems support this and most pipelines do not use it.
Build somewhere you can throw away. An ephemeral runner limits persistence to a single run, so a compromise does not become a foothold.
Going deeper
Do not build on a host that also runs something you care about. A build is arbitrary code execution, and anything sharing that host shares the blast radius — the database, the reverse proxy, the other tenant.
Egress control is the least common and most effective step here. A compromised build needs to send something somewhere; default-deny outbound with an allowlist for your registries makes exfiltration a project rather than a one-liner.
Words used on this pagedefinitions
- PBAC
- Pipeline-Based Access Controls. The permissions available to pipeline steps, as distinct from the permissions of the people who wrote them.
- Ephemeral runner
- A build machine created for one job and destroyed afterwards, so nothing an attacker leaves behind survives.
- Egress control
- Restricting where a machine can send outbound traffic. Usually absent from build environments, which is why exfiltration from them is easy.
Why this matters
Pipeline runners are usually provisioned once, with the union of every permission any job might need. A step that only compiles TypeScript then executes with credentials that can reach the production database, and the difference between 'the build ran' and 'an attacker ran' is nothing at all.
What it looks like in practice
If any of these sound familiar, that is the point — most of them are things somebody did for a sensible reason on a busy afternoon.
- One runner identity used by every job, holding the union of all permissions.
- Build steps executing as root on a host that also runs production workloads.
- Secrets injected into every step of a pipeline rather than the one that needs them.
- Runners with unrestricted network egress, so exfiltration needs no cleverness.
- Long-lived cloud credentials on the runner instead of short-lived scoped ones.
Check your own pipeline
Questions you can actually answer, rather than a maturity score. If you cannot answer one of them, that is itself the finding — and a more useful one than a number.
What could the build step do if it wanted to?
Enumerate the credentials and network reach available to a single step, then compare that to what the step legitimately needs.
Does the build run on a host you care about?
A build is untrusted code execution by design. Anything sharing that host shares its blast radius.
docker context ls
Can the runner reach the internet?
Egress is how a compromised build sends anything anywhere. Default-deny with an allowlist is achievable and rare.
How to fix it
- Scope credentials per step, and prefer short-lived tokens minted for one job.
- Build somewhere you can discard. An ephemeral runner limits persistence to the run.
- Do not build on a host running production. Anything else on that host is inside the blast radius.
- Restrict egress from build environments to the registries and services builds actually need.
Did this get you to an answer?
No text box on purpose — please do not paste production logs anywhere
Risk taxonomy from OWASP Top 10 CI/CD Security Risks (Daniel Krivelevich and Omer Gil, September 2022, CC BY-SA 4.0). Explanations, checks, fixes and definitions written for this site.