Skip to content
Skillpedia
Misc35k · #6207

securing-github-actions-workflows

Hardens GitHub Actions workflows against attacks. Protects secrets and restricts permissions to prevent security risks.

What it does

This feature helps protect your automated workflows (called GitHub Actions) from attacks. It ensures that the tools used are always the same specific versions and that the permissions given to them are the minimum necessary to function, preventing malicious code from being executed.

When to use it

  • ✓When your workflows handle sensitive information (secrets).
  • ✓When your workflows deploy code to production.
  • ✓When you want to prevent changes in branch names or Pull Request titles from causing security issues.

Example of what to ask your AI

“How can I secure my GitHub Actions workflows against attacks?”

Want more? Open the sections below.

How to use

The easiest way: copy the message below and paste it into Claude, ChatGPT, Cursor or any AI. It reads the skill and follows the instructions.

Skill link

https://github.com/mukul975/Anthropic-Cybersecurity-Skills/blob/main/skills/securing-github-actions-workflows/SKILL.md

Ready-to-paste message

Use this skill to help me: https://github.com/mukul975/Anthropic-Cybersecurity-Skills/blob/main/skills/securing-github-actions-workflows/SKILL.md Read the SKILL.md file at that link and follow its instructions for my task.
How it works

It works by verifying that external tools used in your workflows are pinned to specific versions (using a unique code called SHA) and by limiting the permissions the main GitHub Actions token has. It also prevents information from outside (like PR titles) from being used insecurely in commands.

Installation

Easiest way: copy the skill link and paste it into Claude, ChatGPT or Cursor asking it to follow the instructions.

In the terminal (Claude Code, Codex, Cursor), in your project folder:

npx skills add mukul975/Anthropic-Cybersecurity-Skills --skill securing-github-actions-workflows

Or download just the file:

curl -L https://raw.githubusercontent.com/mukul975/Anthropic-Cybersecurity-Skills/main/skills/securing-github-actions-workflows/SKILL.md -o SKILL.md
Technical content (original SKILL.md)

Original text by the author, straight from GitHub.

Securing GitHub Actions Workflows

When to Use

  • When GitHub Actions is the CI/CD platform and workflows need hardening against supply chain attacks
  • When workflows handle secrets, deploy to production, or have elevated permissions
  • When preventing script injection via untrusted PR titles, branch names, or commit messages
  • When requiring audit trails and approval gates for workflow modifications
  • When third-party actions pose supply chain risk through mutable version tags

Do not use for securing other CI/CD platforms (see platform-specific hardening guides), for application vulnerability scanning (use SAST/DAST), or for secret detection in code (use Gitleaks).

Prerequisites

  • GitHub repository with GitHub Actions enabled
  • GitHub organization admin access for organization-level settings
  • Understanding of GitHub Actions workflow syntax and events

Workflow

Step 1: Pin Actions to SHA Digests

# INSECURE: Mutable tag can be overwritten by attacker
- uses: actions/checkout@v4

# SECURE: Pinned to immutable SHA digest
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11  # v4.1.1

# Use Dependabot to auto-update pinned SHAs
# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"
    commit-message:
      prefix: "ci"

Step 2: Minimize GITHUB_TOKEN Permissions

# Set restrictive default permissions at workflow level
name: CI Pipeline
permissions: {}  # Start with no permissions

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read  # Only what's needed
    steps:
      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11

  deploy:
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/main'
    permissions:
      contents: read
      deployments: write
      id-token: write  # For OIDC-based cloud auth
    steps:
      - name: Deploy
        run: echo "deploying"

Step 3: Prevent Script Injection

# VULNERABLE: User-controlled input in run step
- run: echo "PR title is ${{ github.event.pull_request.title }}"

# SECURE: Use environment variable (properly escaped by shell)
- name: Process PR
  env:
    PR_TITLE: ${{ github.event.pull_request.title }}
    PR_BODY: ${{ github.event.pull_request.body }}
  run: |
    echo "PR title is ${PR_TITLE}"
    echo "PR body is ${PR_BODY}"

# SECURE: Use actions/github-script for complex operations
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea
  with:
    script: |
      const title = context.payload.pull_request.title;
      console.log(`PR title: ${title}`);

Step 4: Secure Fork Pull Request Handling

# DANGEROUS: pull_request_target runs with base repo permissions
# on: pull_request_target  # AVOID unless absolutely necessary

# SAFE: pull_request runs in fork context with limited permissions
on:
  pull_request:
    branches: [main]

# If pull_request_target is required, never checkout PR code:
on:
  pull_request_target:
    types: [labeled]

jobs:
  safe-job:
    if: contains(github.event.pull_request.labels.*.name, 'safe-to-test')
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      # NEVER do: actions/checkout with ref: ${{ github.event.pull_request.head.sha }}
      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
        # This checks out the BASE branch, not the PR

Step 5: Protect Secrets and Environment Variables

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production  # Requires approval
    steps:
      - name: Deploy with secret
        env:
          # Secrets are masked in logs automatically
          DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
        run: |
          # Never echo secrets
          # echo "$DEPLOY_KEY"  # BAD
          deploy-tool --key-file <(echo "$DEPLOY_KEY")

      - name: Audit secret access
        run: |
          # Log that secret was used without exposing it
          echo "::notice::Deploy key accessed for production deployment"

Step 6: Implement Workflow Change Controls

# Require CODEOWNERS approval for workflow changes
# .github/CODEOWNERS
.github/workflows/ @security-team @platform-team
.github/actions/ @security-team @platform-team

# Organization settings:
# 1. Settings > Actions > General > Fork PR policies

…
FAQ

What is 'pinning actions to SHA digests'?

It means using a unique, unchangeable code (SHA) to identify a specific version of an external tool, instead of using a version name that could be altered by an attacker.

Why is it important to limit GITHUB_TOKEN permissions?

The GITHUB_TOKEN is an access key that GitHub Actions uses. Limiting its permissions means that even if an attacker gains access to it, the damage they can cause will be smaller, as they will only be able to do what is strictly necessary.

What is 'script injection' and how is it prevented?

It's an attack where untrusted information (like a Pull Request title) is inserted into a command. This is prevented by ensuring this information is treated as text, not executable code, or by using secure tools to process it.

Details

Original description by the author

Hardens GitHub Actions workflows against supply chain attacks, credential theft, and privilege escalation: pinning actions to SHA digests, minimizing GITHUB_TOKEN permissions, protecting secrets, preventing script injection in workflow expressions, and requiring reviewers for workflow changes. Use when hardening GitHub Actions workflows that handle secrets, deploy to production, or run with elevat

repo: mukul975/Anthropic-Cybersecurity-Skills

Popularity

GitHub stars
35k
Ranking position
#6207
License
Apache-2.0
Updated
8/31/2026

Is this skill useful?

0

Sign in to vote.

Comments

  • …

More skills from this repository

Similar skills