Securing Your CI/CD Pipeline: A Practical Guide
A CI/CD pipeline is, by design, a system that runs code you didn't write (dependencies, third- party actions) with credentials that can push to production. That combination makes it one of the highest-leverage places to get security fundamentals right - and one of the most commonly ignored.
Why CI/CD Is a Real Target
- Pipelines routinely hold deploy credentials, cloud provider keys, and package-registry publish tokens - compromise one workflow and you may have compromised production.
- Every dependency your build installs, and every third-party action your workflow calls, runs with the pipeline's own permissions - not sandboxed.
- Pipelines are automated and often under-monitored compared to production systems, so a compromise can persist unnoticed for longer.
Secrets Management
- Never hardcode a credential in a workflow file or commit it "temporarily" - git history is forever, even after a later commit removes it.
- Use your CI provider's secret store (GitHub Actions secrets, GitLab CI/CD variables) rather than
.envfiles checked into the repo. - Scope secrets to the narrowest environment that needs them - a secret available to every branch and every PR is a secret available to anyone who can open a PR.
- Rotate credentials on a schedule, and immediately if a workflow that had access to them is ever modified by an untrusted contributor.
Dependency and Supply Chain Risk
- Pin third-party GitHub Actions to a full commit SHA, not a mutable tag like
@v1- a tag can be moved to point at different, potentially malicious code without your workflow file changing at all. - Treat your build's own dependencies the same way - a compromised transitive dependency runs with full build permissions during
npm install, not just at runtime in production. - Be deliberate about which third-party actions you use - prefer actions maintained by the platform itself or a well-known vendor over a random low-star repository.
Least-Privilege Permissions
The single highest-leverage change most repos can make: default every workflow's token to read-only, and grant write access explicitly only to the specific job that needs it.
The other classic mistake: workflows triggered by pull_request_target or workflow_run that check out and execute code from a fork with write-level permissions. A malicious PR from an external contributor can then run arbitrary code with your repo's own credentials. If a workflow needs elevated permissions, make sure it's not also running untrusted, attacker-controlled code in the same job.
A Practical Hardening Checklist
- Workflow permissions default to read-only, elevated only where explicitly needed
- Third-party actions pinned to a commit SHA, not a mutable tag
- Secrets scoped per-environment, not available to every branch and PR by default
- No workflow runs untrusted fork code with write-level permissions
- Dependencies scanned for known vulnerabilities on every PR, not just periodically
- Credentials rotated on a schedule and immediately after any workflow-file change from an untrusted contributor
Related reading
How to Fix Hardcoded Secrets in Your Codebase
An API key committed to a public (or even private) repo is compromised the moment it's pushed - how Scanverra's repo scanner finds them, and how to rotate and remove them properly.
How to Fix Outdated & Vulnerable Dependencies
Why a dependency with a known CVE sitting in package.json is one of the most common ways production apps get breached, and a practical process for triaging and updating safely.
Scanverra vs. Snyk
A developer-security platform scanning open-source dependencies, source code, containers, and IaC, priced per contributing developer with a capped free tier.
Automate this in your next PR
Run a free repo scan and see outdated dependencies, CVEs, and code quality issues before they ship.
Run a free repo scan