01 · 凭证风险面:从长期令牌到工作负载身份
流水线是组织内权限密度最高的系统:源码读写、制品发布、云资源管理、密钥签名往往集中于同一执行环境。传统做法——生成长期Access Key写入CI变量——意味着任何一次脚本注入或日志泄露都等价于长期失陷(Codecov 2021、Docker Hub 2019的共性教训)。现代基线是OIDC工作负载身份联邦:
| 模式 | 机制 | 风险对比 |
|---|---|---|
| 长期静态令牌 | 云Access Key/ PAT写入CI Secrets,长期有效 | 泄露窗口=有效期全周期;跨仓库复制扩散难追踪;无法精细绑定调用者身份 |
| OIDC联邦(推荐基线) | CI运行时向IdP换取短期JWT(绑定仓库/分支/工作流),云侧角色按token条件授权(GitHub Actions于2021年10月上线OIDC支持;GitLab、Buildkite等随后跟进) | 令牌分钟级过期、调用身份精确绑定、无需在CI存储任何云凭证——静态凭证面趋零 |
落地要点:① 云侧角色信任策略必须校验token的iss/sub/aud与仓库分支组合,防止“任意分支工作流冒领生产角色”;② 环境(Environment)保护规则+必需评审人,把生产发布权限从“能运行流水线”中分离;③ 轮换剩余存量令牌并启用泄露检测(GitHub Secret Scanning、云厂商凭证监控)。
02 · PPE:毒化流水线执行
PPE(Poisoned Pipeline Execution)由Cider Security于2022年系统化提出,并已被OWASP纳入CI/CD安全Top 10(CICD-SEC-4:Poisoned Pipeline Execution),指攻击者无需直接攻陷构建基础设施,而是通过修改流水线定义或输入,使流水线执行恶意步骤。两类形态:
| 形态 | 机制 | 示例 |
|---|---|---|
| Direct PPE | 直接修改仓库内流水线配置文件(.github/workflows/*.yml)触发恶意步骤 | Fork PR篡改workflow后由pull_request_target等事件在目标上下文执行 |
| Indirect PPE | 流水线配置未改,但引用的脚本/配置/标签被篡改,执行时代码变更 | tj-actions/changed-files标签重指(2025年3月,CVE-2025-30066):恶意commit混入后,在开启debug日志的workflow中将密钥打印进日志 |
2.1 tj-actions事件深度复盘(2025年3月,已核实要素)
- 时间线:2025年3月14—15日,该Action的v1—v45.0.7标签被重指向含恶意提交的commit(公开记录的恶意commit哈希为0e58ed8);3月18日CISA将其纳入KEV目录(CVE-2025-30066,CVSS 8.6);关联事件reviewdog/action-setup(CVE-2025-30154)手法相同;
- 影响规模:GitHub平台数据与多家安全机构分析显示约2.3万个公开仓库使用该Action;恶意代码将ACTIONS_*等敏感环境变量(含密钥)写入workflow日志,日志可被具有读取权限者查看;
- 根因链条:后续调查(StepSecurity)显示攻击起点为@tj-actions-bot账号的个人访问令牌(PAT)被攻陷;标签可变引用(未固定commit SHA)+ workflow默认将fork PR上下文中的敏感变量带入日志——两个“低危惯例”叠加成高危事件;
- 防御基线:第三方Action固定到完整commit SHA(而非tag);最小化打印进日志的变量范围;对workflow日志开启密钥遮蔽并限制读取权限;定期审计Actions依赖树。
2.2 事件响应清单(此类事件通用)
| 动作 | 要点 |
|---|---|
| 立即隔离 | 锁定受影响workflow运行记录与日志访问;暂停使用受影响Action版本 |
| 凭证轮换 | 假设所有出现在日志中的密钥已泄露:云角色、注册中心令牌、签名密钥全量轮换并审计使用记录 |
| 溯源排查 | 检查恶意commit进入路径(上游账号/标签机制);评估构建产物是否被污染并重签重建 |
| 对外通报 | 按监管与合同义务评估披露(含CRA/GB/T 43698-2024场景下的供应链通报要求) |
03 · 自托管Runner风险基线
- 拒绝共享持久化Runner执行不可信代码:处理fork PR的job应跑在一次性(ephemeral)Runner上,任务结束即销毁——否则恶意PR可留下持久化后门并污染后续构建(与第4页L3临时性基线同源);
- 网络出口收敛:Runner默认放通互联网是高危配置,按构建需求白名单化出口;防止构建脚本外联C2或回传源码;
- 凭证作用域最小化:自托管Runner上 Secrets按job注入、不落盘;Runner主机禁装无关软件、纳入主机EDR覆盖;
- 公共仓库自托管Runner视为高危:GitHub官方文档明确警告:公共仓库workflow不应在自托管Runner运行不可信PR代码——其所在网络与凭证可能被直接利用。
04 · Secrets管理与仓库侧防护
| 控制 | 说明 |
|---|---|
| 集中式密钥库 | HashiCorp Vault、云厂商Secrets Manager等动态签发数据库/中间件凭证;流水线只获得句柄不接触明文 |
| 推送保护(Push Protection) | GitHub Secret Scanning的推送保护在提交含已知模式密钥时直接阻断——将泄露消灭在入库前(2022年起逐范围开放) |
| 日志遮蔽与审计 | CI平台自动遮蔽打印的Secrets;对遮蔽失败的运行告警(tj-actions事件的核心教训之一) |
| 第三方App/集成审计 | GitHub Apps、Deploy Keys、OAuth授权定期盘点,移除僵尸集成(供应链事件常见初始入口) |
| 包注册中心账户加固 | 维护者强制2FA(PyPI关键项目2022年7月起强制)、发布令牌绑定IP/CI、启用sigstore签名发布(npm支持provenance发布证明) |
05 · 流水线安全核查清单(摘要)
- 云凭证全部从静态令牌迁移至OIDC联邦,角色信任策略校验分支/环境组合;
- 第三方Action固定commit SHA;每月自动审计Action更新与异常变更;
- pull_request_target类事件禁用执行来自fork的不可信代码;
- 生产发布经Environment保护规则+人工评审;签名密钥仅存KMS;
- 所有workflow输出经Secrets遮蔽校验;日志读取权限最小化;
- 自托管Runner一次性化、出口白名单、纳入主机防护。
本节参考来源(第7页)
GitHub Actions OIDC工作负载身份官方文档(2021年10月功能上线):docs.github.com。
Cider Security《Poisoned Pipeline Execution (PPE)》研究(2022年,团队后并入Palo Alto Networks,成果由Legit Security延续):owasp.org/www-project-top-10-ci-cd-security-risks(PPE已收录为CICD-SEC-4)、paloaltonetworks.com/cyberpedia。
CVE-2025-30066(tj-actions/changed-files)与CVE-2025-30154(reviewdog/action-setup)NVD条目:nvd.nist.gov;CISA KEV收录记录:cisa.gov/kev。
Step Security对该事件的分析博客(2025年3月):stepsecurity.io/blog(tj-actions事件分析专文)。
GitHub自托管Runner安全官方警告:docs.github.com。
GitHub Secret Scanning与Push Protection文档:docs.github.com。
Codecov事件官方披露(2021年4月):about.codecov.io/security-update;PyPI 2FA政策公告(2022年):blog.pypi.org。