Gh Actions - Context Script Injections

Tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks

理解风险

GitHub Actions 会在 step 执行前渲染表达式 ${{ … }}。渲染后的值会被粘贴进该 step 的程序(对于 run steps,是一个 shell 脚本)。如果你在 run: 中直接插入不受信任的输入,attacker 将能控制部分 shell 程序并执行 arbitrary commands。

Docs: https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions and contexts/functions: https://docs.github.com/en/actions/learn-github-actions/contexts

要点:

  • 渲染发生在执行之前。run 脚本会在所有表达式解析完后生成,然后由 shell 执行。
  • 许多 contexts 包含取决于触发事件的用户可控字段(issues、PRs、comments、discussions、forks、stars 等)。参见 untrusted input 参考: https://securitylab.github.com/resources/github-actions-untrusted-input/
  • 在 run: 内部对 shell 进行引号转义并不是可靠的防护,因为注入发生在模板渲染阶段。Attackers 可以通过精心构造的输入打破引号或注入操作符。

Vulnerable pattern → RCE on runner

Vulnerable workflow (triggered when someone opens a new issue):

name: New Issue Created
on:
issues:
types: [opened]
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: New issue
run: |
echo "New issue ${{ github.event.issue.title }} created"
- name: Add "new" label to issue
uses: actions-ecosystem/action-add-labels@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
labels: new

如果 attacker 打开一个标题为 $(id) 的 issue,渲染后的步骤变为:

echo "New issue $(id) created"

命令替换在 runner 上运行 id。示例输出:

New issue uid=1001(runner) gid=118(docker) groups=118(docker),4(adm),100(users),999(systemd-journal) created

为什么引用无法保护你:

  • 表达式会先被渲染,然后渲染得到的脚本会被执行。如果不受信任的值包含 $(…)、;"/' 或换行,它仍能改变程序结构,即使你已做了引用。

安全模式 (shell variables via env)

正确的缓解措施:将不受信任的输入复制到环境变量,然后在 run 脚本中使用原生 shell 展开 ($VAR)。不要在命令中用 ${{ … }} 重新嵌入。

# safe
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: New issue
env:
TITLE: ${{ github.event.issue.title }}
run: |
echo "New issue $TITLE created"

注意事项:

  • 避免在 run: 中使用 ${{ env.TITLE }}。那会重新将模板渲染引入命令,从而带来相同的注入风险。
  • 优先通过 env: 映射传递不受信任的输入,并在 run: 中使用 $VAR 引用它们。

可被读者触发的表面(视为不受信任)

仅对公共仓库具有只读权限的账户仍然可以触发许多事件。由这些事件派生的 contexts 中的任何字段,除非另有证明,否则都必须被视为由攻击者控制。示例:

  • issues, issue_comment
  • discussion, discussion_comment (orgs can restrict discussions)
  • pull_request, pull_request_review, pull_request_review_comment
  • pull_request_target (dangerous if misused, runs in base repo context)
  • fork (anyone can fork public repos)
  • watch (starring a repo)
  • Indirectly via workflow_run/workflow_call chains

哪些具体字段被攻击者控制取决于事件。请参考 GitHub Security Lab’s untrusted input 指南:https://securitylab.github.com/resources/github-actions-untrusted-input/

实用建议

  • 尽量减少在 run: 中使用 expressions。优先使用 env: 映射并使用 $VAR。
  • 如果必须转换输入,请在 shell 中使用安全工具(例如 printf %q、jq -r 等)进行,且仍然应从 shell 变量开始。
  • 在将分支名、PR 标题、用户名、标签、讨论标题以及 PR head refs 插入到脚本、命令行参数或文件路径时,要格外小心。
  • 对于 reusable workflows 和 composite actions,采用相同模式:映射到 env,然后引用 $VAR。

References

Tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks