配置文件本应是静态的声明式数据,却在现代软件供应链中成为代码执行的重要入口。2025 年 7 月发生的 eslint-config-prettier npm 包供应链攻击事件,以 7800 万周下载量的规模揭示了配置文件执行风险的严重性 —— 攻击者仅需在 package.json 中添加一行 install 脚本,即可在开发者执行 npm install 时触发恶意代码执行。本文从该案例出发,拆解配置文件执行攻击的技术特征,提出可落地的静态检测策略与分层防护体系。
攻击链拆解:从配置文件到恶意代码执行
eslint-config-prettier 攻击事件的技术路径清晰展示了配置文件执行风险的完整链条。攻击者通过钓鱼邮件获取维护者 npm 账号后,在 9.1.1 等版本中植入了恶意代码。关键改动仅在 package.json 中增加了一个 scripts 字段:
"scripts": {
"install": "node install.js"
}
这一看似无害的配置,使得 npm 在安装依赖时自动执行 install.js。该脚本表面上是日志清理工具,包含大量正常的文件操作代码作为伪装,但核心载荷通过字符串拼接技术隐藏:require('chi' + 'ld_pro' + 'cess')['sp' + 'awn']('rund' + 'll32', [...])。这种拼接方式规避了简单的关键字匹配检测,最终调用 Windows 的 rundll32.exe 加载同目录下的 node-gyp.dll,将执行权转移至原生代码层面。
node-gyp.dll 是一个 PE32+ 可执行文件,攻击者利用 LoadLibrary 和 GetProcAddress 解析导出函数 main 并执行。该 DLL 内部通过 CreateThread 创建独立线程运行混淆代码,被识别为 Scavenger 恶意软件家族,具备文件窃取、凭证收集等能力。值得注意的是,攻击者刻意选择 .dll 扩展名伪装成 Node.js 原生模块(通常以 .node 为后缀),增加了迷惑性。
四层静态检测规则
针对配置文件执行攻击的特征,静态检测需要从以下四个维度建立规则:
第一层:生命周期脚本监控
package.json 中的 preinstall、install、postinstall、prepare 等生命周期脚本是首要检测目标。检测规则应标记任何新增或修改的脚本字段,特别是指向非标准入口文件(如 install.js、setup.js)的配置。对于 ESLint、Prettier 等纯配置类包,若出现安装脚本应立即触发告警 —— 这类包通常不应包含可执行代码。
第二层:可执行文件附件检测
npm 包中包含的二进制文件(.dll、.exe、.so、.dylib)需要重点审查。eslint-config-prettier 案例中,node-gyp.dll 以 1.3MB 的体积随包分发,这在配置类依赖中极不寻常。检测规则应计算包内二进制文件的总大小和数量,对超过阈值的包进行深度扫描。同时,扩展名伪装是常见手法,如将可执行文件命名为 .dll 而非 .node,检测应基于文件头魔数(Magic Number)而非扩展名判断文件类型。
第三层:动态代码执行模式识别
攻击者常使用字符串拼接、编码转换等技术规避静态分析。检测规则应识别以下模式:字符串拼接构建模块名(如 'chi'+'ld_pro'+'cess')、动态属性访问(['sp'+'awn'])、Base64 编码后执行、eval 和 Function 构造器的使用。这些模式在正常配置类包中极少出现,可作为高置信度检测信号。
第四层:网络行为与外部依赖分析
安装时网络请求是载荷投递的常见方式。静态分析应检查脚本中是否包含 HTTP/HTTPS 请求、DNS 解析、以及可疑的外部域名访问。同时,应分析包的依赖树深度和可疑依赖(如新增的非常规依赖、GitHub 直接引用而非 npm registry 来源)。
三阶段防护体系
静态检测是发现风险的手段,而防护体系需要在软件生命周期的多个阶段建立屏障:
开发阶段:前置拦截
开发者本地环境是供应链攻击的第一道防线。工具如 SafeDep 的 pmg(Package Manager Guard)可在安装前拦截恶意包,通过本地策略引擎实时分析 package.json 和包内容,对命中检测规则的包拒绝安装并输出详细告警。建议团队在 .npmrc 中配置 ignore-scripts=true 作为默认策略,仅对经过审计的包通过 --ignore-scripts=false 显式放行。
CI/CD 阶段:门禁管控
持续集成流水线是阻断恶意代码进入代码库的关键节点。vet 等工具可作为 CI 门禁,在 Pull Request 阶段扫描依赖变更。配置应包含:
- 对新增依赖执行静态分析扫描
- 校验
package-lock.json与package.json的一致性 - 禁止未经审计的
install/postinstall脚本 - 集成 OSV 漏洞数据库进行已知恶意包检测
AI Agent 阶段:智能防护
随着 AI 编程助手和 Agent 的普及,自动安装依赖的场景大幅增加。通过 MCP(Model Context Protocol)Server 集成,可在 AI IDE(如 VS Code + Copilot)中嵌入安全检测能力。当 AI 建议安装某个包时,MCP Server 实时查询安全数据库,对存在风险的包给出替代建议或直接阻止安装操作。
可落地参数清单
基于上述策略,以下是可直接落地的配置参数与检查清单:
npm 配置(.npmrc)
ignore-scripts=true
package-lock=true
audit-level=moderate
静态检测规则阈值
| 检测项 | 告警阈值 | 阻断阈值 |
|---|---|---|
| 生命周期脚本新增 | 任何配置类包 | 包含可疑代码模式 |
| 二进制文件大小 | 单文件 >500KB | 单文件 >1MB |
| 字符串拼接模式 | >3 处拼接 | 构建敏感 API 调用 |
| 外部网络请求 | 安装时任意请求 | 非 HTTPS 或可疑域名 |
CI/CD 检查清单
- 运行
npm ci而非npm install确保 lockfile 严格匹配 - 执行
npm audit并设置失败阈值(建议audit-level=high) - 扫描
node_modules中的.dll、.exe等可执行文件 - 校验包签名与 npm provenance 数据
- 对比依赖树与上次发布的 SBOM 差异
风险边界与持续演进
静态检测并非万能。高度混淆的代码、基于 WebAssembly 的载荷、以及利用合法工具链(如 node-gyp)的复杂攻击可能绕过现有规则。此外,过度严格的检测策略可能影响正常开发效率,需要在安全与体验间取得平衡。
eslint-config-prettier 事件表明,供应链安全不能仅依赖事后响应。从配置文件这一最小攻击面入手,建立覆盖开发、CI、AI Agent 的全流程防护,配合可量化的检测规则,才能有效降低配置文件执行风险对软件供应链的威胁。
参考来源
- SafeDep: "eslint-config-prettier Compromised: How npm Package with 30 Million Downloads Spread Malware"
- OWASP Cheat Sheet Series: "NPM Security"
内容声明:本文无广告投放、无付费植入。
如有事实性问题,欢迎发送勘误至 i@hotdrydog.com。