Securing your CI/CD pipeline: a practical guide
By VA2PT Team, . 8 min read

Your CI/CD pipeline is the most powerful system you own. It has access to your source code, your cloud, your secrets and your production environment, and whatever it builds is trusted automatically by everything downstream. That power is exactly why attackers have shifted their attention to it. This article explains, in plain terms, why the pipeline is such a valuable target and the practical controls that turn it from a soft spot into a strong one.
The problem
A traditional attack compromises one system. A pipeline attack compromises every release. If someone can influence what your build produces — by tampering with a dependency, stealing a pipeline credential, or slipping a change into the build steps — they can ship malicious code to all of your users at once, signed and blessed by your own release process. This is the "supply chain" risk you have seen in the news, and it is serious precisely because the output is trusted by default.
The uncomfortable truth is that many pipelines are more privileged and less guarded than the production systems they deploy to. They hold long-lived cloud credentials, run code from every pull request, and pull in hundreds of third-party dependencies, often with fewer controls than a single production server.
Why it happens
Pipelines accumulate risk quietly, for understandable reasons:
- Convenience beats least privilege. Giving the pipeline broad admin access makes everything "just work," so it happens early and is never walked back.
- Untrusted input runs with trusted access. A pipeline that builds pull requests is running code contributed from outside, sometimes with access to secrets, which is a dangerous combination.
- Dependencies are trusted blindly. Builds pull the latest version of packages from public registries, so a compromised or malicious package flows straight into your artifact.
- No record of what produced an artifact. When something is wrong, teams cannot tell which commit, which dependencies and which steps produced a given build, so they cannot reason about trust.
Give the pipeline the least privilege it can do the job with
Start by shrinking what the pipeline can reach. It should hold no long-lived cloud keys; instead, use short-lived credentials issued through federation (OpenID Connect), so the pipeline exchanges its identity for a temporary token scoped to exactly what a given job needs.
# GitHub Actions assuming a scoped AWS role via OIDC — no stored cloud keys
permissions:
id-token: write # allows the OIDC token to be issued
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/deploy-staging
aws-region: ap-south-1
Separate duties by environment: the job that deploys to staging must not be able to deploy to production, and production deploys should require an approval. Treat the permission the pipeline holds the same way you would treat an employee's access — as little as possible, reviewed regularly.
Protect the inputs: code, dependencies and runners
Three inputs decide whether you can trust the output.
- Dependencies. Pin versions and use a lockfile so a build is reproducible and a package cannot silently change under you. Scan dependencies for known vulnerabilities on every build, and prefer a vetted internal mirror for critical packages over pulling straight from the public registry.
- Pull-request builds. Do not expose production secrets to workflows triggered by pull requests from outside contributors, and require review before such workflows run with any privileged access.
- The runner. The machine that executes the build is itself a target. Keep it patched, isolated, and ephemeral where possible, so each build starts from a clean, known state and leaves nothing behind for the next one.
Make artifacts verifiable
The end goal is that everything downstream can prove an artifact came from your real pipeline and has not been altered. Sign your build artifacts and container images, and record where each one came from — the commit, the dependencies and the build steps that produced it. This provenance is the idea behind frameworks like SLSA, and it turns "we think this build is fine" into "we can prove this build is fine." When something does go wrong, provenance is also what lets you find every affected release quickly instead of guessing.
What to do this week
- Replace any long-lived cloud keys stored in your CI with short-lived, federated credentials (OIDC).
- Split deploy permissions by environment and require an approval step for production.
- Add a lockfile and dependency scanning to your build, and pin versions so builds are reproducible.
- Make sure pull-request workflows from outside contributors cannot read production secrets.
- Start signing your release artifacts or images, even in a basic form, so downstream systems can verify them.
When to bring in a partner
Hardening a pipeline touches identity, cloud permissions, build tooling and developer workflow at once, which is why teams often stall on it. Locking down CI/CD, moving to short-lived credentials, and adding artifact signing and provenance is a core part of our DevSecOps work, and it complements a VAPT engagement that tests whether the pipeline can actually be abused. Done once, properly, it closes off one of the highest-impact attack paths a modern company has, and it keeps your releases trustworthy as the team grows.
- ci-cd
- supply-chain
- devsecops
- pipeline-security
- slsa