2026年5月13日,OpenAI 发布安全公告,正式回应此前 TanStack npm 供应链攻击波及自身一事。结论是:两台员工设备被攻陷,但用户数据、生产系统、软件产物均未发现异常。尽管如此,OpenAI 依然选择全面轮换代码签名证书,并要求 macOS 用户在6月12日前完成应用更新。
这不是一次"没事就好"的轻描淡写——它暴露了 npm 供应链攻击的穿透力,以及代码签名证书在防御体系中的关键地位。
攻击是怎么穿透到 OpenAI 的
TanStack 是前端生态中广泛使用的开源库家族(Router、Query、Table 等),npm 周下载量达数百万次。攻击者通过某种方式获取了 TanStack 维护者的发布权限,在合法包名下推送了携带恶意代码的新版本。这类攻击的杀伤链很清晰:
- 劫持发布通道——拿到 npm publish 权限(凭据泄露、权限滥用或社会工程)。
- 植入恶意代码——在正常功能代码中夹带后门,通常在 install 或 postinstall 钩子触发。
- 沿依赖链扩散——任何直接或间接依赖该包的项目,
npm install时自动拉取恶意版本。
OpenAI 的两台员工设备,正是在开发环境中执行了 npm install 拉取到被篡改的 TanStack 包后受影响的。这说明:即便最终生产系统未被入侵,开发环境的"第一道防线"已经被突破。
为什么没有造成更大损失
OpenAI 公告强调三点未发现异常:
- 用户数据未泄露——受影响设备是员工开发机,不含生产数据库访问凭据或用户数据直连通道。
- 生产系统未入侵——开发环境与生产环境之间存在隔离(网络分段、CI/CD 管线审核),恶意代码未能跨越边界。
- 软件产物未被篡改——最终交付给用户的二进制/安装包,经过独立签名和校验流程,未使用受影响设备上的构建产物。
这三条"未发现"背后,是多层防御在起作用:环境隔离、CI 管线控制、代码签名验证。但"未发现"不等于"不可能"——这正是 OpenAI 选择轮换证书的原因。
代码签名证书轮换意味着什么
代码签名证书是操作系统验证应用来源和完整性的信任锚点。macOS、Windows 在启动应用时,会校验签名证书链。如果证书私钥泄露或可能泄露,攻击者理论上可以签发看起来"来自 OpenAI"的恶意软件。
轮换证书的操作成本很高:
- 旧证书签发的所有已发布版本将失去信任链(用户更新后才能识别新证书)。
- macOS 用户必须在截止日期前更新,否则 Gatekeeper 会因为证书失效而拒绝启动应用。
- CI/CD 管线中所有签名步骤需要重新配置。
OpenAI 设定6月12日为截止日期,本质上是在用时间窗口换安全余量——给用户足够的更新时间,同时确保旧证书在此日期后彻底失效。
开发者如何自查和加固
这次事件对任何依赖 npm 生态的团队都是一记警钟。以下是可直接操作的加固步骤。
1. 检查项目中是否曾拉取过被篡改的 TanStack 版本
# 查看项目中 TanStack 相关包的安装历史版本
# 将 @tanstack/react-query 替换为你实际使用的包名
npm ls @tanstack/react-query @tanstack/router @tanstack/table 2>/dev/null
# 检查 lockfile 中是否有可疑版本号(异常高的版本跳跃)
grep -E "@tanstack/(react-query|router|table)" package-lock.json | head -20
# 如果使用 pnpm
pnpm ls @tanstack/react-query @tanstack/router @tanstack/table
如果发现版本号异常(比如从 v5.x 突然出现 v5.x.99 或类似的可疑版本),立即锁定到已知安全版本:
# 锁定到确认安全的版本,然后重新安装
npm install @tanstack/react-query@5.62.0 --save-exact
npm install
2. 在 CI 中启用 npm 供应链安全审计
在 GitHub Actions 或任何 CI 管线中加入自动审计步骤,每次 install 前检查已知漏洞和可疑包:
# .github/workflows/supply-chain-audit.yml
name: Supply Chain Audit
on:
pull_request:
push:
branches: [main]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: npm ci
- name: Run npm audit
run: npm audit --audit-level=high
# 如果发现 high/critical 漏洞,CI 直接失败
- name: Check for suspicious postinstall scripts
run: |
# 扫描所有依赖中的 postinstall/preinstall 钩子
SUSPICIOUS=$(npm ls --all --json 2>/dev/null | \
python3 -c "
import json, sys
data = json.load(sys.stdin)
for name, info in data.get('dependencies', {}).items():
scripts = info.get('scripts', {})
for hook in ['preinstall', 'install', 'postinstall']:
if hook in scripts:
print(f'{name}: {hook} -> {scripts[hook]}')
")
echo "$SUSPICIOUS"
# 人工审查输出,任何非必要脚本都应标记
- name: Verify package integrity with sigstore
run: |
# 使用 npm sigstore 验证包签名(需 npm >= 10)
npx sigstore verify @tanstack/react-query@5.62.0 || echo "签名验证失败,请审查"
3. 锁定依赖版本,禁止浮动版本号
// package.json — 禁止使用 ^ 或 ~ 前缀
{
"dependencies": {
// 错误做法:浮动版本,npm install 可能拉到新版本
// "@tanstack/react-query": "^5.62.0"
// 正确做法:精确锁定
"@tanstack/react-query": "5.62.0"
},
// 强制 npm ci 使用 lockfile,禁止隐式升级
"scripts": {
"install:locked": "npm ci --ignore-scripts"
}
}
--ignore-scripts 会跳过所有 postinstall 钩子,这是供应链攻击最常见的触发点。如果某些包确实需要 postinstall(如 native 二进制编译),单独白名单处理。
4. 如果你的团队也使用代码签名证书
轮换流程的核心步骤(以 macOS 应用为例):
# 1. 生成新的代码签名密钥对和 CSR
openssl req -new -newkey rsa:4096 -keyform PEM \
-keyout new-signing-key.pem -out signing.csr \
-subj "/O=YourCompany/CN=Your App Signing Certificate"
# 2. 向 Apple Developer Program 提交 CSR,获取新证书
# (通过 Apple Developer Portal 手动操作)
# 3. 导入新证书到签名环境
security import new-signing-key.pem -k ~/Library/Keychains/signing.keychain
# 4. 更新 CI/CD 签名步骤,使用新证书 Identity
# 在 codesign 命令中指定新证书的 SHA-1 fingerprint
codesign --sign "NEW_CERTIFICATE_IDENTITY" \
--force --timestamp --options runtime \
dist/YourApp.app
# 5. 通知所有用户在截止日期前更新
# 在应用内弹窗、邮件通知、官网公告三管齐下
供应链攻击的防御清单
| 措施 | 作用 | 实施难度 |
|---|---|---|
npm ci + --ignore-scripts |
阻止 postinstall 钩子执行 | 低 |
| 精确锁定版本号 | 防止浮动版本拉取恶意更新 | 低 |
CI 中 npm audit |
自动拦截已知漏洞 | 低 |
| sigstore 包签名验证 | 验证包来源真实性 | 中 |
| 开发环境与生产环境网络隔离 | 阻止攻击横向移动 | 中 |
| 代码签名证书定期轮换 | 限制私钥泄露的影响窗口 | 高 |
| npm publish 权限最小化 | 减少凭据泄露面 | 中 |
OpenAI 这次"只损失两台开发机"的结果,不是运气——是环境隔离和签名验证在起作用。但两台设备被攻陷本身,说明开发环境的第一道防线(npm install 时的信任模型)已经失守。对任何依赖开源生态的团队来说,加固这条防线不是可选项,是必修课。
6月12日之前,如果你是 OpenAI macOS 应用用户,更新应用。如果你是 npm 生态的开发者,今天就可以跑一遍上面的审计脚本。