DevOps Security

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.

Mitigation: Use secret managers. Never echo secrets. Limit secret access to specific jobs.

Untrusted Code Execution

PRs from forks can execute malicious code in your CI with access to secrets.

Mitigation: Require approval for fork PRs. Use pull_request_target carefully. Limit permissions.

Dependency Confusion

Attackers publish malicious packages with internal package names to public registries.

Mitigation: Scope packages. Use private registries. Pin exact versions.

Compromised Actions

Third-party GitHub Actions can be compromised or malicious.

Mitigation: Pin actions to commit SHA. Audit action source. Minimize third-party actions.

GitHub Actions Security

Pin Actions to SHA

Avoid
uses: actions/checkout@v4
Better
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11

Tags can be moved. SHA is immutable.

Limit Token Permissions

Avoid
permissions: write-all
Better
permissions:\n contents: read\n pull-requests: write

Principle of least privilege. Only grant what's needed.

Don't Trust PR Input

Avoid
run: echo ${{ github.event.pull_request.title }}
Better
run: echo "$TITLE"\nenv:\n TITLE: ${{ github.event.pull_request.title }}

Direct interpolation allows command injection.

Protect Secrets from Forks

Avoid
on: pull_request (with secrets)
Better
on: pull_request_target with environment protection

Fork PRs can exfiltrate secrets. Require manual approval.

Secrets Management

Use GitHub Secrets or external secret managers
Hardcode secrets in workflow files
Limit secret access to specific environments
Make secrets available to all workflows
Rotate secrets regularly
Use the same secrets for years
Use OIDC for cloud authentication
Store long-lived cloud credentials
Audit secret access logs
Ignore who/what accesses secrets

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.

Free Security Scan

Frequently 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.

Last updated: January 16, 2026