flawopen.com/Incidents/shai-hulud-npm-worm-september-2025
●
npm ecosystem · CWE-506 / CWE-829 · September 2025 · 严重
安全研究 · FlawOpen
Shai-Hulud:2025 年 9 月的 npm 蠕虫与安装时的信任边界
2025 年 9 月,Shai-Hulud 利用遭入侵的 npm 维护者账户和恶意 postinstall 钩子窃取凭据,并发布更多受感染的包。[1]
💡 通俗易懂的原理解析 (ELI5)
想象工厂收到一箱零件,箱子自带会自动执行的拆箱指令。指令复制工厂的发货证件,再用它们向其他工厂寄出被篡改的箱子。禁止自动拆箱指令能堵住这个入口,但零件本身在使用前仍需检查。[1]
核心概念与专有名词
Lifecycle hook- 九月的攻击通过 npm postinstall 在安装时执行恶意代码。这是包提供的行为,不是带 CVE 编号的 npm 内存漏洞。
Publishing credential- npm 令牌具有账户或包授予的权限。被盗的发布权限帮助蠕虫传播;有效期、范围和 MFA 要求取决于配置。
Trusted publishing / OIDC- OIDC 允许经过授权的 CI 流程取得短期发布凭据,而不用保存 npm 令牌。但遭入侵的授权流程仍不安全。
框架映射
事件演进时间线
攻击执行流程分解
源代码对比:漏洞与安全实现
这是安全的 Python 安装计划对照:两段代码均不执行 npm、不读取凭据,也不访问注册表。示例依据 npm v10 文档。强化计划要求已审核的锁定文件,抑制安装脚本,不继承环境变量。真实运行器还须提供已知的 npm 可执行文件,并隔离主目录与配置,不能挂载凭据或敏感文件。--ignore-scripts 不能保证以后导入的代码或显式运行的脚本安全;锁定文件也不能证明代码无害。
存在漏洞的实现
def install_plan(reviewed_lockfile, inherited_env):
# 仅返回计划:不会安装软件包或执行命令。
return {"argv": ["npm", "ci"],
"env": dict(inherited_env)}
加固后的安全修复
def install_plan(reviewed_lockfile, inherited_env):
# 仅返回计划:不会安装软件包或执行命令。
if reviewed_lockfile is not True:
raise ValueError("Review the lockfile before installation")
return {"argv": ["npm", "ci", "--ignore-scripts"],
"env": {}}