CI/CD Pipeline Security & GitHub Actions Automation Runbook
The battle-tested production manual for GitHub Actions CI/CD: Harden workflow security against supply chain attacks, eliminate long-lived credentials with OIDC, optimize build caching, and implement matrix testing.
1. Pipeline Supply Chain Hardening & Action Pinning
# ANTI-PATTERN: Mutable tag can be rewritten by attackers
# uses: actions/checkout@v4
# PRODUCTION PATTERN: Immutable SHA with readable version comment
- name: Checkout Code
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
fetch-depth: 1 # Shallow clone to save runner disk and bandwidthTools like Dependabot or Renovate automatically update pinned commit SHAs while preserving version comments.
| Security Rule | Implementation | Vulnerability Prevented | Copy |
|---|---|---|---|
| Least Privilege Permissions | permissions: contents: read | Prevents rogue scripts from pushing malicious tags | |
| Commit SHA Pinning | uses: action@<commit-sha> | Defeats compromised action tag hijacking | |
| OpenID Connect (OIDC) | Temporary cloud role assumption | Eliminates permanent cloud access keys in Secrets | |
| Script Injection Defense | Pass env vars, never inline ${{ github.event }} | Stops arbitrary bash command execution via PR titles |
2. Preventing Script Injection Attacks
# CRITICAL VULNERABILITY (Script Injection):
# - run: echo "PR Title is: ${{ github.event.pull_request.title }}"
# PRODUCTION SAFE PATTERN: Pass untrusted values strictly as environment variables
- name: Process Pull Request Title Safely
env:
PR_TITLE: ${{ github.event.pull_request.title }}
run: |
# Bash treats $PR_TITLE purely as a string payload, neutralizing shell injection
echo "Processing PR: $PR_TITLE"Environment variables prevent bash from interpreting quotes and semicolons as shell command boundaries.
3. High-Velocity Dependency & Build Caching
- name: Setup Node.js with Automatic npm Caching
uses: actions/setup-node@60edb5dd545a775178f5252478332d7967d24b31 # v4.0.2
with:
node-version: 22.x
cache: "npm"
cache-dependency-path: "package-lock.json"
- name: Clean Install Dependencies
# npm ci is faster, strictly reproducible, and fails if lockfile is out of sync
run: npm ci
- name: Build Static Production Assets
run: npm run buildactions/setup-node includes built-in dependency caching that eliminates custom actions/cache boilerplate.
4. Matrix Multi-Platform & Node Version Testing
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
# If one combination fails, continue running the others to see all test results
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [20.x, 22.x]
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@60edb5dd545a775178f5252478332d7967d24b31
with:
node-version: ${{ matrix.node-version }}
cache: "npm"
- run: npm ci
- run: npm testfail-fast: false ensures developers discover all cross-platform bugs in a single run.
5. Passwordless Cloud Deployments with OIDC
name: Production Cloud Deployment
on:
push:
branches: [main]
# Grant the runner permission to request a short-lived OIDC ID token
permissions:
id-token: write # Mandatory for OIDC federation
contents: read # Mandatory to clone repository
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- name: Assume Cloud IAM Role via OIDC
uses: aws-actions/configure-aws-credentials@e3ddf4a3c70e81768204c180fb5f00f0163c7438
with:
role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsDeployRole
aws-region: eu-west-1
- name: Sync Static Assets to Cloud Storage
run: aws s3 sync ./dist s3://mayonlinetools-production --deleteZero static passwords in GitHub Secrets; the cloud provider trusts GitHub OIDC claims (repository, ref, commit).
Related Free Online Tools
Put these techniques into practice immediately with our privacy-first browser utilities:
Convert and validate complex YAML GitHub Actions workflow definitions into structured JSON.
Compose clean, well-formatted YAML configurations with customizable indentation and quoting.
Ensure deployment shell scripts and runner binaries have correct 755 execution permissions.