CI/CD Security
Secure your build pipelines. Prevent supply chain attacks, protect secrets, and harden your GitHub Actions.
CI/CD Security Risks
Secret Exposure
Secrets logged to console, exposed in artifacts, or accessible to forked PRs.
Untrusted Code Execution
PRs from forks can execute malicious code in your CI with access to secrets.
Dependency Confusion
Attackers publish malicious packages with internal package names to public registries.
Compromised Actions
Third-party GitHub Actions can be compromised or malicious.
GitHub Actions Security
Pin Actions to SHA
uses: actions/checkout@v4uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11Tags can be moved. SHA is immutable.
Limit Token Permissions
permissions: write-allpermissions:\n contents: read\n pull-requests: writePrinciple of least privilege. Only grant what's needed.
Don't Trust PR Input
run: echo ${{ github.event.pull_request.title }}run: echo "$TITLE"\nenv:\n TITLE: ${{ github.event.pull_request.title }}Direct interpolation allows command injection.
Protect Secrets from Forks
on: pull_request (with secrets)on: pull_request_target with environment protectionFork PRs can exfiltrate secrets. Require manual approval.
Secrets Management
Secure Your Deployed Apps
A secure pipeline is only part of the story. Make sure your deployed application doesn't expose the secrets your CI/CD protects.
Get Starter ScanFrequently Asked Questions
Can forked PRs access my secrets?
By default, pull_request events from forks don't have access to secrets. But pull_request_target does give secret access—and it runs attacker-controlled code. This is a common attack vector. If you need secrets for PR checks, use environment protection rules requiring manual approval for forks.
Should I pin GitHub Actions to SHA?
Yes, for security-critical workflows. Tags like @v4 can be moved by the action author (or an attacker who compromises their account). SHA pins are immutable. The tradeoff is you don't get automatic updates—use Dependabot to manage action updates.
How do I prevent command injection in workflows?
Never directly interpolate untrusted input like PR titles or branch names into run commands. Use environment variables instead: set env: TITLE: ${{ github.event.pull_request.title }} then reference as $TITLE in the script. This prevents shell injection.
What's OIDC authentication and should I use it?
OIDC (OpenID Connect) lets GitHub Actions authenticate to cloud providers without storing credentials. GitHub issues a short-lived token that proves the workflow's identity. AWS, GCP, and Azure all support this. Yes, use it—it eliminates the risk of leaked long-lived credentials.
How do I audit my CI/CD security?
Review: 1) Workflow permissions—should be minimal, 2) Third-party actions—pin to SHA, audit sources, 3) Secret access—who can access, when rotated, 4) Fork handling—are secrets protected, 5) Artifact exposure—what's uploaded and who can access. Tools like StepSecurity can help automate this.
Related Resources
Last updated: January 16, 2026