Weaponizing GitHub Actions

Niek Palm
Niek Palm

💥 Supply Chain Attacks in the Wild

🔥

SolarWinds

2020

Compromised build system injected malicious code into legitimate software updates affecting 18,000+ organizations including government agencies and Fortune 500 companies

💀

CodeCov

2021

Docker image compromised in CI/CD pipeline, stealing credentials and secrets from hundreds of customers

tj-actions/changed-files

2025

Attackers compromised maintainer bot token, manipulated version tags to point to malicious commits, exfiltrating CI/CD secrets from 23,000+ repositories using this popular GitHub Action

🎭

S1ngularity (Nx)

2025

Exploited pull_request_target injection to steal npm token, published malicious Nx packages, weaponized AI tools for secrets exfiltration, exposed 1000s of secrets and private repos

🤖 What is GitHub Actions?

"GitHub Actions automates your software development workflow, letting you build, test, and deploy code directly from your GitHub repository. Its tight integration with GitHub has made it one of the most widely adopted CI/CD solutions."

⚙️ Example workflow

name: GitHub Actions Example

on: [push, pull_request]                           # 1

jobs:
  build:
    runs-on: [ubuntu-latest]                       # 2
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v5                    # 3
        
    - name: Install dependencies
      run: npm ci                                  # 4
      
    - name: Run tests
      run: npm test                                # 4

🔍 What's happening?

  1. Trigger: on push or pull_request
  2. Runner: GitHub hosted fleet
    ubuntu-latest
  3. Third party action: checkout@v5
  4. Run script: npm ...

🚀 Actions Everywhere

From development to deployment - GitHub Actions powers our entire software lifecycle

🏗️

Build & compile code

🐳

Build containers

🧪

Run unit tests

🎭

Run E2E tests

🛡️

Security scanning

🔍

Code quality checks

📦

Publish packages

☁️

Deploy to cloud

🔄

Manage infrastructure

🚀

Release automation

📚

Generate docs

🌐

Deploy static sites

🔄

Update dependencies

🏷️

Tag & version

🤖

Automate workflows

📊

Generate reports

📧

Send notifications

🔐

Manage secrets

🎯

Issue triage

🌍

Multi-platform builds

🔥 What can go wrong?

name: Check Changed Files

on: [pull_request]

jobs:
  check-changes:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4.0.0
    
    - name: Get changed files
      uses: tj-actions/changed-files@v45.0.7
      id: changed-files
      with:
        files: |
          src/**
          docs/**
    
    - name: Process changes
      run: echo "Changed files: ${{ steps.changed-files.outputs.all_changed_files }}"

🎯 Repository takeover

🚀 Push Malicious Code

✨ Create Releases

🏷️ Rewrite Tags

Repository Takeover Attack

✅ Secure third-party actions

🔒 Lock SHA

🔍 Verify Integrity

🤖 Manage with Dependabot

🛡️ Minimal Privilege

name: Secure Workflow

on: [pull_request]

jobs:
  secure-build:
    runs-on: ubuntu-latest
    steps:
      # SHA-pinned action for security
    - uses: actions/checkout@08c690...      # v5.0.0 ← SECURE
    
    - name: Get changed files
      # SHA-pinned action for security
      uses: tj-actions/changed-files@24d32f... # v47 ← SECURE
      
    - name: Process changes
      ...

🤔 What can go wrong?

name: Issue Logger

on:
  issues:
    types: [opened]

jobs:
  log-issue:
    runs-on: ubuntu-latest
    steps:
    - name: Log issue details
      run: |
        echo "Issue: ${{ github.event.issue.title }}"
        echo "Description: ${{ github.event.issue.body }}"

✅ The solution

name: Issue Logger

on:
  issues:
    types: [opened]

jobs:
  log-issue:
    runs-on: ubuntu-latest
    steps:
    - name: Log issue details
      env:                                              # ← NEW
        ISSUE_TITLE: ${{ github.event.issue.title }}    # ← NEW
        ISSUE_BODY: ${{ github.event.issue.body }}      # ← NEW  
      run: |
        echo "Issue: $ISSUE_TITLE"                      # ← CHANGED
        echo "Description: $ISSUE_BODY"                 # ← CHANGED

🛡️ How to Fix Security Issues

⚙️

Guardrails by Configuration

Set workflow permissions to read-only by default, require approval for external contributors, and enable security hardening in repository settings.

Restrictive

🔒

GitHub Advanced Security

Built-in code scanning, secret scanning, and dependency review that automatically detects vulnerabilities in your workflows and provides remediation guidance.

Detective & Preventive

Zizmor

Open-source static analyzer with CLI that integrates seamlessly into CI/CD pipelines and works well with pre-commit hooks for early detection.

Detective & Preventive

🔧 Zizmor static analysis for GitHub Actions

📋

Extensive rule set for comprehensive scanning

⚙️

Highly configurable to fit your needs

🔗

Integrates with GHAS seamlessly

🛠️

Use with CLI, IDE, pre-commit or Actions

🔒 Beyond Pipeline Security

  • 🏃 Runtime security
    GitHub runners are ephemeral but unrestricted, self-hosted runners need hardening
  • 🛡️ Repository controls
    Branch protection, required reviews, and access policies guard your code
  • ⚠️ Third-party dependencies
    Actions and code from external sources execute in your trusted context

🔗 Resources and links

QR Code

Scan for resources

💬 🍻 🙏