Skip to content
AI & Agents
Skill

/github-actions-hardening

Security hardening reviewer for GitHub Actions workflow files (.github/workflows/*.yml). Reasons about the Actions threat model that pattern matchers and general code linters miss — untrusted-input script injection, privileged triggers running fork code, mutable action

From plugin
awesome-copilot
41k200 skills200 agents

Claude Code

$ npx -y skills add github/awesome-copilot --skill github-actions-hardening --agent claude-code

SKILL.md

github-actions-hardening.SKILL.md
name: github-actions-hardening
description: Security hardening reviewer for GitHub Actions workflow files (.github/workflows/*.yml). Reasons about the Actions threat model that pattern matchers and general code linters miss — untrusted-input script injection, privileged triggers running fork code, mutable action references, and over-scoped tokens. Use this skill when asked to review, audit, harden, or secure a GitHub Actions workflow, when writing a new workflow, or for any request like "is this workflow safe?", "review my CI for security issues", "why is pull_request_target dangerous here?", "pin my actions", or "lock down GITHUB_TOKEN permissions". Covers script injection via ${{ }} interpolation, pull_request_target / workflow_run privilege escalation, SHA-pinning of third-party actions, least-privilege permissions, GITHUB_ENV/GITHUB_OUTPUT injection, secret exposure, OIDC over long-lived credentials, and self-hosted runner exposure on public repositories.

GitHub Actions Hardening

A focused security reviewer for GitHub Actions workflows. It reasons about the *Actions-specific* threat model — where trust boundaries live in trigger types, token scopes, and string interpolation — rather than the application-code vulnerabilities a general security scanner looks for. Most workflow risks are invisible to language linters because the dangerous code is the YAML itself and the way GitHub expands `${{ }}` expressions into a shell before your script runs.

When to Use This Skill

Use this skill when the request involves:

  • Reviewing, auditing, or hardening any file under `.github/workflows/`
  • Authoring a new workflow and wanting it secure by default
  • A workflow that uses `pull_request_target`, `workflow_run`, or `issue_comment` triggers
  • Questions about `GITHUB_TOKEN` permissions or the `permissions:` key
  • Pinning actions to commit SHAs vs tags vs branches
  • Handling untrusted input (issue titles, PR bodies, branch names, commit messages) in `run:` steps
  • OIDC / cloud authentication from Actions, or secret handling in CI
  • Self-hosted runners on public repositories
  • Any request like "is this workflow safe?", "secure my CI", or "review this GitHub Action"

The Core Insight

In a workflow, **`${{ <expr> }}` is expanded by the runner into the script *before* the shell executes it.** So a step like:

- run: echo "Title: ${{ github.event.issue.title }}"

is not passing a variable — it is *pasting attacker-controlled text directly into your shell command*. An issue titled `"; <attacker-command> #` is concatenated into the script and executed. This single mechanism is the most common real-world Actions vulnerability, and models routinely generate it. Treat every `${{ }}` that contains data an outside contributor can influence as a code-injection sink.

Execution Workflow

Follow these steps **in order** for every workflow reviewed.

Step 1 — Map the Triggers and Trust Level

Read every `on:` trigger and classify the workflow's privilege:

  • `push`, `pull_request` (from same repo) → runs with the contributor's own trust
  • `pull_request` from a **fork** → runs with a **read-only** token, **no secrets** (safe by design)
  • `pull_request_target`, `workflow_run`, `issue_comment`, `issues` → run in the context of the

**base repository** with a **read/write token and full access to secrets**, but can be **triggered by outside contributors**. These are the dangerous triggers.

Read `references/triggers-and-privilege.md` for the full trust matrix.

Step 2 — Hunt for Script Injection

For every `run:` block, every `script:` in `actions/github-script`, and every input to a custom action, list the `${{ }}` expressions and check whether any resolve to attacker-controllable data. High-risk contexts include:

  • `github.event.issue.title`, `github.event.issue.body`
  • `github.event.pull_request.title`, `github.event.pull_request.body`, `.head.ref`, `.head.label`
  • `github.event.comment.body`, `github.event.review.body`
  • `github.event.pages.*.page_name`, `github.event.commits.*.message`, `github.event.head_commit.*`
  • `github.head_ref` and any `github.event.*` field a fork author can set

Read `references/injection.md` for the complete sink list and the safe-pattern fixes.

Step 3 — Check Privileged Triggers Don't Execute Untrusted Code

If a `pull_request_target` or `workflow_run` workflow checks out PR/fork code (`ref: ${{ github.event.pull_request.head.sha }}`) **and then runs it** (build, test, install scripts, `npm install` with lifecycle scripts, etc.), that is remote code execution against a privileged token. Flag it as CRITICAL. The safe pattern is to split into two workflows: an unprivileged `pull_request` workflow that runs the untrusted code, and a privileged `workflow_run` workflow that only consumes its results.

Step 4 — Audit `permissions:`

  • If there is **no** `permissions:` block, the workflow inherits the repository default, which may

be read/write to everything. Flag it.

  • Recommend a top-level `permissions: {}` (deny-all) or `contents: read`, then grant the minimum

per job (e.g. `pull-requests: write` only on the job that comments).

  • Flag any `permissions: write-all` or broad `write` scopes that the steps don't actually need.

Read `references/permissions-and-tokens.md` for the per-scope guidance and OIDC setup.

Step 5 — Audit Action References (Supply Chain)

For every `uses:`:

  • **Third-party actions** (not `actions/*` or `github/*`) MUST be pinned to a full 40-character

commit SHA, not a tag or branch. Tags and branches are mutable; a compromised upstream action can rewrite `v1` to malicious code that runs with your token and secrets.

  • First-party `actions/*` are lower risk but SHA-pinning is still the hardened recommendation.
  • Flag `@main`, `@master`, or any branch reference as HIGH — that is "latest" and can change under

you at any time.

  • Note the human-readable version in a trailing comment: `uses: foo/bar@<sha> #
Read more
@github
Ships withawesome-copilot

A community-created collection of custom agents, instructions, skills, hooks, workflows, and plugins to supercharge your GitHub Copilot experience.

41k200 skills200 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
41.2k
Star history of github/awesome-copilot on GitHub, a chart by star-history.com

Other skills on awesome-copilot.

acreadiness-assess

acreadiness-assess

Run the AgentRC readiness assessment on the current repository and produce a static HTML dashboard at reports/index.html. Wraps…

More skills from other plugins.

1password

1password

Set up and use 1Password CLI for sign-in, desktop integration, and reading or injecting secrets.

openclaw2w393k
@openclaw@openclawInstall Skill

Questions about github-actions-hardening.

Which coding agents can use github-actions-hardening?
github-actions-hardening installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.