self-hosted runner 默认不安全,因其绕过 github 托管 runner 的沙箱、网络隔离与自动清理机制,易被恶意 fork pr 触发任意命令并危害宿主机。

self-hosted runner 为什么默认不安全
GitHub Actions 的 self-hosted runner 运行在你自己的机器上,但它的执行权限和网络环境完全由你控制——这意味着它天然绕过 GitHub 托管 runner 的沙箱、网络隔离和自动清理机制。一旦 workflow 中的 run 步骤被恶意 PR 触发(比如通过 fork 提交的 PR),runner 就可能执行任意命令,读取宿主机凭证、访问内网服务、甚至反向连接攻击者服务器。
如何防止 fork PR 自动触发敏感 job
这是最常见也最容易被忽略的风险点。默认情况下,fork 发起的 PR 也能触发你的 workflow,且其 secrets 不会注入(这点没错),但 run 脚本本身仍会在你的私有 runner 上执行。
- 在 workflow 文件中显式添加
if: github.event_name == 'pull_request' && github.repository_owner == 'your-org' || github.event_name != 'pull_request'条件判断 - 更稳妥的做法是:对所有敏感 job(比如部署、发布、访问内部 API)加
permissions:限制,并配合concurrency和env隔离 - 禁用 fork PR 的自动运行:在仓库 Settings → Actions → General → “Workflow permissions” 中关闭 “Allow GitHub Actions to create and approve pull requests”,并勾选 “Restrict workflows to selected actions”
runner 进程该用什么用户身份运行
绝不能用 root 或当前登录用户直接启动 run.sh。runner 进程若以高权限运行,一个 rm -rf / 或 curl | bash 就能毁掉整台机器。
- 创建专用低权限系统用户,例如
gh-runner,无 shell、无 sudo 权限、home 目录仅限 runner 工作区 - 用
systemd管理时,在 service 文件中明确指定User=gh-runner和Group=gh-runner - 工作目录(
_work)和 runner 根目录必须属主为该用户,且禁止其他用户写入:chmod 755 /opt/my-runner,chmod 700 /opt/my-runner/_work
runner 和 workflow 之间怎么隔离敏感信息
secrets 是加密传给 runner 的,但一旦解密进环境变量,就可能被 ps aux、进程内存 dump 或日志泄露。尤其当多个 workflow 共用一个 runner 时,缓存、临时文件、环境变量残留都可能交叉污染。
立即学习“Python免费学习笔记(深入)”;
- 避免在
env:下直接暴露${{ secrets.MY_TOKEN }};改用steps[*].with.args或短生命周期的子 shell 传参 - 禁用 runner 的
cleanup跳过逻辑:确保每次 job 后_work目录被彻底清空(检查cleanup日志是否含Removing work directory) - 不要复用 runner 实例跑 CI 和 CD:部署类 job 必须独占 runner,或使用标签(
runs-on: [self-hosted, deploy])物理隔离
真正难的不是配置几行 YAML,而是持续保证 runner 所在机器的最小权限状态、网络出向白名单、以及对 workflow 拉取内容的零信任——哪怕只改了一行 run,也要当成新代码审查。










