github-actions-hardening

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

GitHub Actions Hardening

GitHub Actions 安全强化

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.
一款专注于GitHub Actions工作流的安全审查工具。它针对Actions特有的 威胁模型进行分析——包括触发器类型、令牌范围和字符串插值中的信任边界——而非通用安全扫描器关注的应用代码漏洞。大多数工作流风险无法被语言检查工具发现,因为危险代码存在于YAML本身,以及GitHub在脚本运行前将
${{ }}
表达式扩展为shell命令的方式中。

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"
当请求涉及以下内容时,可使用此技能:
  • 审查、审计或强化
    .github/workflows/
    下的任何文件
  • 编写新工作流并希望默认具备安全性
  • 使用
    pull_request_target
    workflow_run
    issue_comment
    触发器的工作流
  • 关于
    GITHUB_TOKEN
    权限或
    permissions:
    关键字的问题
  • 将Actions固定到提交SHA、标签或分支的对比
  • run:
    步骤中处理不可信输入(议题标题、PR内容、分支名称、提交信息)
  • 从Actions进行OIDC/云身份验证,或CI中的密钥处理
  • 公共仓库中的自托管运行器
  • 任何诸如“这个工作流安全吗?”“加固我的CI”或“审查这个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:
yaml
- 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.
在工作流中,
${{ <expr> }}
会被运行器在shell执行脚本之前扩展到脚本中
。因此,如下步骤:
yaml
- run: echo "Title: ${{ github.event.issue.title }}"
并非传递变量——而是将攻击者可控的文本直接粘贴到你的shell命令中。如果议题标题为
"; <attacker-command> #
,则会被拼接到脚本中并执行。这是现实中最常见的Actions漏洞,且模型经常会生成此类漏洞。请将所有包含外部贡献者可影响数据的
${{ }}
视为代码注入风险点。

Execution Workflow

执行流程

Follow these steps in order for every workflow reviewed.
请按以下顺序步骤审查每个工作流。

Step 1 — Map the Triggers and Trust Level

步骤1 — 映射触发器与信任级别

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.
读取每个
on:
触发器并分类工作流的权限:
  • push
    pull_request
    (来自同一仓库)→ 使用贡献者自身的信任权限运行
  • 来自fork仓库
    pull_request
    → 使用只读令牌运行,无密钥访问(设计上安全)
  • pull_request_target
    workflow_run
    issue_comment
    issues
    → 在基础仓库的上下文中运行,拥有读写令牌和完整密钥访问权限,但可能被外部贡献者触发。这些是危险的触发器。
请阅读
references/triggers-and-privilege.md
获取完整的信任矩阵。

Step 2 — Hunt for Script Injection

步骤2 — 排查脚本注入

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.
对于每个
run:
块、
actions/github-script
中的每个
script:
以及自定义Action的每个输入,列出所有
${{ }}
表达式并检查是否有解析为攻击者可控的数据。高风险场景包括:
  • 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
    以及fork作者可设置的任何
    github.event.*
    字段
请阅读
references/injection.md
获取完整的风险点列表和安全模式修复方案。

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

步骤3 — 检查特权触发器是否执行不可信代码

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.
如果
pull_request_target
workflow_run
工作流检出PR/fork代码(
ref: ${{ github.event.pull_request.head.sha }}
并运行(构建、测试、安装脚本、带生命周期脚本的
npm install
等),则会针对特权令牌执行远程代码。标记为CRITICAL(严重)。安全模式是拆分为两个工作流:一个非特权的
pull_request
工作流运行不可信代码,一个特权的
workflow_run
工作流仅消费其结果。

Step 4 — Audit
permissions:

步骤4 — 审计
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.
  • 如果没有
    permissions:
    块,工作流会继承仓库默认权限,可能对所有内容拥有读写权限。标记此问题。
  • 建议使用顶层
    permissions: {}
    (拒绝所有权限)或
    contents: read
    ,然后为每个作业授予最小必要权限(例如,仅在需要评论的作业中设置
    pull-requests: write
    )。
  • 标记任何
    permissions: write-all
    或步骤实际不需要的宽泛
    write
    权限范围。
请阅读
references/permissions-and-tokens.md
获取权限范围指南和OIDC设置说明。

Step 5 — Audit Action References (Supply Chain)

步骤5 — 审计Action引用(供应链)

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> # v2.1.0
    .
Read
references/supply-chain.md
for pinning, Dependabot for actions, and artifact/cache risks.
对于每个
uses:
  • 第三方Action(非
    actions/*
    github/*
    )必须固定到完整的40字符提交SHA,而非标签或分支。标签和分支是可变的;被攻陷的上游Action可将
    v1
    重写为恶意代码,使用你的令牌和密钥运行。
  • 第一方
    actions/*
    风险较低,但仍建议固定SHA版本以强化安全。
  • 标记
    @main
    @master
    或任何分支引用为HIGH(高风险)——这代表“最新版本”,随时可能发生变化。
  • 在末尾注释中添加可读版本:
    uses: foo/bar@<sha> # v2.1.0
请阅读
references/supply-chain.md
获取版本固定、Actions的Dependabot配置以及工件/缓存风险的相关内容。

Step 6 — Check Secret and Output Handling

步骤6 — 检查密钥与输出处理

  • No secrets echoed, printed, or written to logs; no
    set -x
    /
    bash -x
    in steps that touch secrets.
  • Secrets must not be passed to steps that run untrusted code or to untrusted third-party actions.
  • Untrusted multiline data written to
    $GITHUB_ENV
    or
    $GITHUB_OUTPUT
    can inject environment variables or step outputs — use the random-delimiter heredoc form and never write raw user input.
  • actions/checkout
    leaves a token on disk by default; set
    persist-credentials: false
    when the job later runs untrusted code.
  • 不得在日志中回显、打印或写入密钥;在涉及密钥的步骤中不得使用
    set -x
    /
    bash -x
  • 不得将密钥传递给运行不可信代码的步骤或不可信第三方Action。
  • 写入
    $GITHUB_ENV
    $GITHUB_OUTPUT
    的不可信多行数据可能注入环境变量或步骤输出——请使用随机分隔符的heredoc格式,切勿写入原始用户输入。
  • actions/checkout
    默认会在磁盘上留下令牌;当作业后续运行不可信代码时,请设置
    persist-credentials: false

Step 7 — Produce the Report

步骤7 — 生成报告

Output findings using the format in
references/report-format.md
: a severity summary table first, then grouped findings with file, the exact offending YAML, the risk in plain English, and a concrete before/after fix. Never auto-apply changes — present them for review.
使用
references/report-format.md
中的格式输出结果:首先是严重性汇总表,然后是按分组的问题,包含文件、确切的问题YAML代码、用通俗易懂的语言描述风险,以及具体的修复前后对比。切勿自动应用更改——请提供方案供审核。

Severity Guide

严重性指南

SeverityMeaningExample
🔴 CRITICALToken/secret theft or RCE reachable by an outside contributor
pull_request_target
checking out and running fork code;
${{ github.event.* }}
in a
run:
on a privileged trigger
🟠 HIGHExploitable supply-chain or scope problemThird-party action on a mutable tag/branch;
write-all
permissions; injection sink on
issue_comment
🟡 MEDIUMRisk under conditions or chainingMissing
permissions:
block; secret reachable by a non-fork PR author
🔵 LOWHardening gap, low direct riskFirst-party action not SHA-pinned;
persist-credentials
left default on a non-privileged job
⚪ INFOObservation, not a vulnerabilityVersion comment missing next to a pinned SHA
严重性含义示例
🔴 CRITICAL外部贡献者可获取令牌/密钥或执行远程代码
pull_request_target
检出并运行fork代码;特权触发器上
run:
中的
${{ github.event.* }}
🟠 HIGH可被利用的供应链或权限范围问题第三方Action使用可变标签/分支;
write-all
权限;
issue_comment
上的注入风险点
🟡 MEDIUM特定条件下或需链式触发的风险缺失
permissions:
块;非fork PR作者可访问密钥
🔵 LOW加固缺口,直接风险低第一方Action未固定SHA版本;非特权作业中
persist-credentials
保留默认设置
⚪ INFO观察结果,非漏洞固定SHA旁缺失版本注释

Output Rules

输出规则

  • Always show a findings summary table (counts by severity) first.
  • Group by issue type, not by file.
  • Be exact — quote the offending line and give the line location.
  • Always pair every CRITICAL/HIGH with a concrete corrected YAML snippet.
  • Never claim a fork
    pull_request
    is dangerous just because it runs untrusted code — it has no secrets and a read-only token. Reserve CRITICAL for the privileged triggers.
  • If the workflow is already hardened, say so and list what was checked.
  • 必须首先显示问题汇总表(按严重性统计数量)。
  • 按问题类型分组,而非按文件分组。
  • 精确描述——引用问题行并给出行号位置。
  • 必须为每个CRITICAL/HIGH级问题搭配具体的修正后YAML代码片段。
  • 切勿仅因为fork的
    pull_request
    运行不可信代码就判定其危险——它无密钥且使用只读令牌。仅对特权触发器标记CRITICAL。
  • 如果工作流已完成加固,请明确说明并列出已检查的内容。

Reference Files

参考文件

Load these as needed:
  • references/triggers-and-privilege.md
    — Trust matrix for every trigger, why
    pull_request_target
    and
    workflow_run
    are privileged, and the two-workflow safe pattern.
    • Search patterns:
      pull_request_target
      ,
      workflow_run
      ,
      issue_comment
      ,
      fork
      ,
      secrets
      ,
      read-only token
      ,
      trust boundary
  • references/injection.md
    — Full list of attacker-controllable
    ${{ }}
    contexts and the
    env:
    -variable safe pattern for each sink (
    run
    ,
    github-script
    , action inputs).
    • Search patterns:
      script injection
      ,
      github.event
      ,
      head_ref
      ,
      issue title
      ,
      env
      ,
      intermediate variable
      ,
      actions/github-script
  • references/permissions-and-tokens.md
    GITHUB_TOKEN
    scopes, least-privilege
    permissions:
    recipes per job type, and OIDC for cloud auth instead of long-lived secrets.
    • Search patterns:
      permissions
      ,
      GITHUB_TOKEN
      ,
      write-all
      ,
      contents: read
      ,
      id-token
      ,
      OIDC
      ,
      least privilege
  • references/supply-chain.md
    — SHA-pinning third-party actions, Dependabot for
    github-actions
    , artifact and cache poisoning across
    workflow_run
    , and self-hosted runner exposure.
    • Search patterns:
      SHA pin
      ,
      uses
      ,
      mutable tag
      ,
      Dependabot
      ,
      download-artifact
      ,
      cache
      ,
      self-hosted runner
  • references/report-format.md
    — Output template: summary table, finding cards, and before/after remediation blocks.
    • Search patterns:
      report
      ,
      format
      ,
      finding
      ,
      summary
      ,
      remediation
      ,
      before
      ,
      after
按需加载以下文件:
  • references/triggers-and-privilege.md
    — 所有触发器的信任矩阵,解释
    pull_request_target
    workflow_run
    为何属于特权触发器,以及双工作流安全模式。
    • 搜索关键词:
      pull_request_target
      ,
      workflow_run
      ,
      issue_comment
      ,
      fork
      ,
      secrets
      ,
      read-only token
      ,
      trust boundary
  • references/injection.md
    — 攻击者可控的
    ${{ }}
    场景完整列表,以及每个风险点(
    run
    ,
    github-script
    , Action输入)的
    env:
    变量安全模式。
    • 搜索关键词:
      script injection
      ,
      github.event
      ,
      head_ref
      ,
      issue title
      ,
      env
      ,
      intermediate variable
      ,
      actions/github-script
  • references/permissions-and-tokens.md
    GITHUB_TOKEN
    权限范围,按作业类型划分的最小权限
    permissions:
    配置示例,以及使用OIDC进行云身份验证替代长期密钥的方案。
    • 搜索关键词:
      permissions
      ,
      GITHUB_TOKEN
      ,
      write-all
      ,
      contents: read
      ,
      id-token
      ,
      OIDC
      ,
      least privilege
  • references/supply-chain.md
    — 第三方Action的SHA版本固定、
    github-actions
    的Dependabot配置、
    workflow_run
    间的工件和缓存投毒,以及自托管运行器暴露风险。
    • 搜索关键词:
      SHA pin
      ,
      uses
      ,
      mutable tag
      ,
      Dependabot
      ,
      download-artifact
      ,
      cache
      ,
      self-hosted runner
  • references/report-format.md
    — 输出模板:汇总表、问题卡片、以及修复前后对比块。
    • 搜索关键词:
      report
      ,
      format
      ,
      finding
      ,
      summary
      ,
      remediation
      ,
      before
      ,
      after