Hotdry.

Article

配置文件中的可执行代码:npm 供应链攻击的静态检测与防护策略

以 eslint-config-prettier 供应链攻击为案例,剖析 package.json 等配置文件执行代码的风险,提供四层静态检测规则与三阶段防护体系的工程化落地参数。

2026-06-08security

配置文件本应是静态的声明式数据,却在现代软件供应链中成为代码执行的重要入口。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+ 可执行文件,攻击者利用 LoadLibraryGetProcAddress 解析导出函数 main 并执行。该 DLL 内部通过 CreateThread 创建独立线程运行混淆代码,被识别为 Scavenger 恶意软件家族,具备文件窃取、凭证收集等能力。值得注意的是,攻击者刻意选择 .dll 扩展名伪装成 Node.js 原生模块(通常以 .node 为后缀),增加了迷惑性。

四层静态检测规则

针对配置文件执行攻击的特征,静态检测需要从以下四个维度建立规则:

第一层:生命周期脚本监控

package.json 中的 preinstallinstallpostinstallprepare 等生命周期脚本是首要检测目标。检测规则应标记任何新增或修改的脚本字段,特别是指向非标准入口文件(如 install.jssetup.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 编码后执行、evalFunction 构造器的使用。这些模式在正常配置类包中极少出现,可作为高置信度检测信号。

第四层:网络行为与外部依赖分析

安装时网络请求是载荷投递的常见方式。静态分析应检查脚本中是否包含 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.jsonpackage.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"

security

内容声明:本文无广告投放、无付费植入。

如有事实性问题,欢迎发送勘误至 i@hotdrydog.com