yarn.lock 里的依赖有安全漏洞,我该手动改它吗?

博主奥杰 阅读 19

最近用 GitHub 的 Dependabot 扫描项目,发现 yarn.lock 里有几个底层依赖有中危漏洞。但这些包不是我直接装的,是被其他依赖带进来的。我试过删掉 node_modules 和 yarn.lock 重新 install,但漏洞还是在。是不是应该手动编辑 yarn.lock 把版本号改掉?听说这不推荐,但又不知道该怎么正确处理。

我来解答 赞 2 收藏
二维码
手机扫码查看
2 条解答
闲人子璐
别手动改 yarn.lock,这玩意儿是 yarn 根据 package.json 和依赖树自动生成的,你改完下次 install 就被覆盖了,白忙活。

正确的做法是:先定位是哪个直接依赖带进来的漏洞包,然后升级这个直接依赖,或者用 yarn 的 override 机制强制指定安全版本。

举个例子,假设漏洞包是 lodash,版本是 4.17.15(有中危漏洞),而它被 some-package 带进来,版本是 ^2.3.0

你可以:

1. 先试试升级 some-package,看它新版本是否用的是安全版 lodash
yarn add some-package@latest


2. 如果 some-package 没更新,或者你不想动它,就用 yarn 的 resolutions 字段强制指定 lodash 版本
在 package.json 里加个字段:
{
"name": "your-project",
"version": "1.0.0",
"resolutions": {
"lodash": "4.17.21"
},
...
}


3. 然后删掉 node_modules 和 yarn.lock,重新装
rm -rf node_modules yarn.lock
yarn install


注意:resolutions 是全局生效的,所有子依赖都会用你指定的 lodash 版本,所以别乱填,确认下新版本没 breaking change。

最后跑一遍 yarn audit 看漏洞是不是真没了。
点赞 2
2026-02-25 16:16
❤钰文
❤钰文 Lv1
这个问题的关键是:yarn.lock 里出现漏洞依赖,通常不是你手动改版本号能解决的,因为 yarn.lock 是由依赖解析结果生成的,手动改会破坏一致性,还可能被下次 install 覆盖掉。正确做法是先让依赖树重新计算出安全版本,再同步更新 lock 文件。

先说说原理:yarn 的 lock 文件本质是「精确版本快照」,它保证每次安装都用完全一样的依赖树。当某个间接依赖(transitive dependency)有漏洞时,问题往往出在「上层依赖声明的版本范围太宽」,导致 yarn 无法自动升级到修复版。比如你的项目直接用了 foo@1.2.0,而 foo@1.2.0 依赖 vulnerable-pkg@^1.0.0,但 vulnerable-pkg 的 1.0.0 和 1.0.1 都有漏洞,只有 1.1.0 修复了——可只要 foo 没升级到用 vulnerable-pkg@^1.1.0 的版本,yarn 就不会主动跳过去。

所以手动改 vulnerable-pkg 的版本号在 lock 文件里是危险操作,比如你改成 vulnerable-pkg@1.1.0,但 foo 声明的是 ^1.0.0,下次 yarn install 会检测到 lock 里版本和解析结果不一致,可能直接重写回去,或者更糟——引入不兼容的版本组合导致运行时崩溃。

正确的处理流程是分三步走:

第一步:确认漏洞依赖的实际来源
运行 yarn why <包名>,比如 yarn why vulnerable-pkg,会输出整个依赖链,告诉你哪个直接依赖 transitively 引进了这个包。这步很重要,因为后续升级必须针对源头。

第二步:尝试升级上层依赖到已修复的版本
去那个上层包的 GitHub 发布页(比如 foo 的 release notes),找有没有发布说明写着「fixed security issue in vulnerable-pkg」。如果有,直接升级你的 package.json 里对 foo 的版本要求。比如从 "foo": "^1.2.0" 改成 "foo": "^1.3.0"(假设 1.3.0 用了安全版的 vulnerable-pkg)。改完后删掉 node_modulesyarn.lock,再跑 yarn install

如果上层包没发新版本呢?这时候有几种方案:

方案 A:用 yarn set resolution 强制指定版本(推荐)
这是 yarn 提供的官方 way to go。比如发现 vulnerable-pkg 的 1.1.0 是安全的,你可以运行:

yarn set resolution vulnerable-pkg@^1.0.0 1.1.0


注意这里的 ^1.0.0 是指「哪个版本范围的依赖请求」,不是包名本身。yarn 会把这个决议写进 yarn.lock__metadata 或直接在依赖项里加一行 resolution: "1.1.0",这样后续 install 都会强制用这个版本,不会被上层版本范围覆盖。这比手动改 lock 安全得多,因为 yarn 知道这是你显式指定的。

方案 B:升级直接依赖,或换用替代包
比如 foo 已经不维护了,可以考虑换 bar 这个同功能但依赖树干净的包。或者自己 fork foo,改 package.json 里对 vulnerable-pkg 的版本要求,发布成 foo-fixed 临时用着(不推荐长期,除非你是核心维护者)。

方案 C:最后手段:用 resolutions 字段(谨慎)
package.json 里加 resolutions 字段,比如:

{
"name": "your-project",
"dependencies": {
"foo": "^1.2.0"
},
"resolutions": {
"vulnerable-pkg": "1.1.0"
}
}


注意这里写的是包名和目标版本,yarn 会全局强制所有地方用这个版本。但要小心:如果不同上层依赖要求的 vulnerable-pkg 接口不一致(比如 1.0.0 有 oldMethod(),1.1.0 改成 newMethod()),就可能运行时报错。所以先确认 vulnerable-pkg 的 changelog 是否有 breaking change。

第三步:验证依赖树是否干净
yarn why vulnerable-pkg 再看一遍,确认现在用的是 1.1.0;再跑 yarn audit(yarn 1.7+ 支持)检查是否还有漏洞。如果 audit 显示还有中危以上漏洞,可以加 --level=high 优先处理高危。

补充一个常见误区:很多人以为删了 yarn.lock 就能「刷新」依赖树,其实不一定。如果 package.json 里版本范围太宽(比如 ^0.0.1),yarn 可能重新安装时又选了旧版。所以永远要先确保 package.json 里直接依赖的版本足够新,或者用 resolutions 锁死关键包。

最后提醒:改完之后别忘了 commit package.jsonyarn.lock,不然下次 CI 又会拉到旧 lock 文件。GitHub Dependabot 本身也支持自动提 PR 升级依赖,可以开启它的 security updates 功能,比手动处理省事得多——虽然有时候它提的 PR 里 resolutions 要你自己再补上,但至少比从零开始强。

对了,如果你用的是 yarn 2 或 3(Berry),流程略有不同:lockfile 格式变了,yarn set resolution 换成 yarn config set resolutions,但思路完全一样:别动 lock 文件本身,用工具生成决议。不过现在新项目尽量用 yarn 3 吧,对漏洞修复更友好,虽然 migrate 过程有点疼……
点赞 1
2026-02-24 17:00