Skip to content

fix(deps): nanoid 顶到 3.3.x 补丁线,清掉 GHSA-2v37-7h3g-55p8 (#6506) - #6538

Merged
hotlong merged 1 commit into
mainfrom
claude/issue-6529-nanoid-advisory
Aug 8, 2026
Merged

fix(deps): nanoid 顶到 3.3.x 补丁线,清掉 GHSA-2v37-7h3g-55p8 (#6506)#6538
hotlong merged 1 commit into
mainfrom
claude/issue-6529-nanoid-advisory

Conversation

@hotlong

@hotlong hotlong commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Fixes #6506

单号更正:本 PR 最初指向 #6529。经 PM 复核,#6529#6506 的重复单(#6506 于 02:39:37Z 记录,早 34 分钟),已关闭为 duplicate,故正文改指 #6506。分支名与提交信息里残留的 6529 字样是历史痕迹 —— ⛔ 未改写已推送的历史(不 force-push)。工作本身、文件面、验收条款均未变。

OSV 门红在锁文件上,所以它对每一个 open PR 都生效,与各 PR 的改动内容无关。处置照 #6427(dompurify)的先例:在 pnpm-workspace.yaml 加一条 override 把 nanoid 顶到补丁线,⛔ 不用 osv-scanner.toml 加豁免消红(该文件一字未动,仍是零豁免)。

一、公告复核(不采信单据里的数字,自己重测)

本地用 osv-scanner v2.3.8 —— 与 .github/workflows/validate-deps.yml 里 pin 的 action 同一版本 —— 加同样的 --lockfile=pnpm-lock.yaml 参数,在当前 origin/main(61478b9)上复现:

Scanned /home/user/objectstack-6529/pnpm-lock.yaml file and found 1387 packages
Loaded filter from: /home/user/objectstack-6529/osv-scanner.toml

Total 1 package affected by 1 known vulnerability (0 Critical, 1 High, 0 Medium, 0 Low, 0 Unknown) from 1 ecosystem.
1 vulnerability can be fixed.

| OSV URL                             | CVSS | ECOSYSTEM | PACKAGE | VERSION | FIXED VERSION | SOURCE         |
| https://osv.dev/GHSA-2v37-7h3g-55p8 | 8.2  | npm       | nanoid  | 3.3.16  | 3.3.17        | pnpm-lock.yaml |
EXIT=1

包数(1387)、CVSS(8.2)、版本、修复版本、退出码与单据里的 CI 读数逐项一致,且 osv-scanner.toml 的过滤器确实被加载而没有豁免这条。前提成立。

公告本体(取自 OSV 官方数据集):GHSA-2v37-7h3g-55p8 / CVE-2026-67213nanoid: custom generators can loop indefinitely when size is zero —— 自定义字母表生成器在 size 为零时无限循环,即攻击者可影响 size 时的拒绝服务。

它带两条受影响区间,这一点值得写明:

区间 introduced fixed
1 0 3.3.17
2 4.0.0 5.1.6

此处只有第一条是活的:

  • 3.3.16 唯一由 postcss@8.5.25 间接引入 —— 全锁文件只有一条 nanoid: 边(postcss@8.5.25 的 dependencies),没有第二个消费者;
  • 四个 driver 直接声明的 nanoid: ^6.0.0(driver-mongodb / driver-sql / driver-sqlite-wasm / driver-turso)高于第二条区间的修复线 5.1.6,本就不受影响 —— 这也正是扫描只点名 3.3.16、没点名 6.0.0 的原因。

二、加的 override 行,以及上界为什么是这个形状

'nanoid@<4.0.0': '^3.3.17'

check:override-consistency 的两份普查是这个形状的机器佐证:自失效选择器普查列出 30 条里的 14 条,nanoid@<4.0.0 不在其中零消费者普查列出 4 条,nanoid@<4.0.0不在其中(它有 postcss 这个真实消费者)。

三、解析版本位移 —— 实测,并写明比较集大小

⚠️ 「应该不会动」不算证据,负向断言若比较集为空会空洞地通过。所以比较集大小与位移结果一并列出。改前 / 改后各解析一次 pnpm-lock.yaml,逐键比对三个互相独立的面:

比较面 比较集大小 位移
packages 键(解析出的 name@version 1387 1 —— nanoid@3.3.16nanoid@3.3.18
snapshots 键(含 peer 上下文的解析实例) 1387 1 —— 同上
importer 边(各 workspace 包的声明 specifier + 解析版本) 746 0

nanoid 之外零位移,合计 3520 个受比对的键/边。比较集非空这一点本身也可交叉验证:packages 的 1387 与 osv-scanner 自己报的 found 1387 packages 相同,说明比对的正是扫描器扫的那个集合。

^3.3.17 在 3.x 内浮到最新,落到 3.3.18(npm 的 legacy dist-tag),高于修复线,同样清掉公告。nanoid@6.0.0 原样保留,已单独复核。

锁文件真实 diff 只有 9 行(5 增 4 删):overrides 块加一行、packages 条目与 integrity、snapshots 键、以及 postcss 的那条边。

四、改后复跑扫描(⛔ 不是靠豁免)

同一个 v2.3.8 二进制、同一份漏洞库、同样的 --lockfile=pnpm-lock.yaml

Scanned /home/user/objectstack-6529/pnpm-lock.yaml file and found 1387 packages
Loaded filter from: /home/user/objectstack-6529/osv-scanner.toml

No issues found
EXIT=0

git status --porcelain osv-scanner.toml 无输出 —— 该文件一字未动,check-osv-exemptions.mjs 仍报「零豁免(the intended steady state)」。这正是 osv-scanner.toml 头部与 #6506 都引到的那条规矩:advisory 有 fixed version 时走「取修复」,不进豁免账本

说明:本容器的出网策略拒绝 api.osv.dev(CONNECT 403),故扫描走 --offline-vulnerabilities + 官方 GCS 漏洞库(可达)。扫描器版本、参数、被扫锁文件、加载的过滤器均与 CI 一致,且改前读数与 CI 逐项吻合,可视为等价复跑;CI 上的 Validate Package Dependencies 会在本 PR 上以真正的在线库再判一次(本 PR 改了 pnpm-lock.yaml / pnpm-workspace.yaml,命中该 workflow 的 paths: 过滤)。

五、正反向验证(先声明,再运行)

声明写在任何一次扫描与任何一次改锁之前:

声明 实测 一致
改前扫描 恰好 1 条,nanoid 3.3.16,退出码 1;6.0.0 不被点名 完全如此
改后扫描 0 条,退出码 0,且非经豁免达成 No issues found,EXIT=0,toml 未动
解析版本位移 仅 nanoid 一处,落到 3.x 最新(预判 3.3.18);6.0.0 不动 3.3.16 → 3.3.18,其余 0 位移,6.0.0 不动
选择器形状 省下界、上界在 4.0.0 major 边界 如此,且不进自失效普查

四项全部与声明一致,无需改写声明。

六、锁文件独占面复核

⚠️ 锁文件是全仓独占面,旧读数不予沿用。推送前对当时全部 18 个 open PR 的 head 分支逐一实测 git diff --name-only origin/main...origin/[分支] -- pnpm-lock.yaml pnpm-workspace.yaml

18 个分支全部无输出,含 release PR #6208changeset-release/main)。无竞争,可推。

七、门禁

全部在 git add -A 之后跑:

结果
pnpm install --frozen-lockfile ✅ exit 0;其后 git status --porcelain 只剩我这两个已暂存改动,无未暂存漂移 —— 锁文件与 workspace 文件自洽
pnpm check:override-consistency ✅ exit 0;自检 17 断言通过;5 条已发布 manifest 声明全部解析到 override target
pnpm lint ✅ exit 0
pnpm check:nul-bytes ✅ 6113 个受追踪文本文件,无裸控制字节
node scripts/check-osv-exemptions.mjs --self-test + 本体 ✅ 零豁免
node scripts/check-changeset-fixed.mjs ✅ 与 69 个 public 包同步
改动文件控制字节自扫 grep -naP 无命中

八、changeset

不加 changeset,改用 skip-changeset 标签 —— 与 #6427 完全同形:同样两个文件(pnpm-workspace.yaml + pnpm-lock.yaml)、同样 9 行锁文件 diff、同样是纯间接依赖,没有任何可发布包的声明区间发生变化(importer 边位移实测为 0),因此对下游安装没有可发布的行为改变。#6427 落的标签是 dependencies / size/s / skip-changeset,无 changeset。

九、#6506 那条 postcss 提醒的实测(立单人自注「没有实测」)

#6506 提醒:「overrides 里已有 'postcss@<9.0.0': '^8.5.10',而 postcss 8.5.25 已经在这条 pin 之上,所以抬 postcss 未必能解决,直接 pin nanoid 更直接」,并注明该点未经实测。既然要求自测,结论如实写在这里:处置结论对,但给出的理由只对一半。

  • npm 上 postcss 最新的 8.x 是 8.5.26latest dist-tag 亦是它),而 8.5.26 声明的正是 nanoid: ^3.3.17(8.5.22–8.5.25 都还是 ^3.3.16)。所以抬 postcss 确实也能清掉这条公告 —— 「未必能解决」这半句不成立,不宜作为下一位的依据。
  • 锁文件停在 8.5.25 而没浮到 8.5.26,与 pin 的下界无关:8.5.25 已满足 ^8.5.10,pnpm 不会主动重解一个已锁定且仍满足区间的版本。
  • 但直接 pin nanoid 仍是更好的那条路,理由比原文更强:抬 postcss 会让一个与公告无关的解析版本发生位移(postcss 8.5.25 → 8.5.26),直接违反本单「nanoid 之外零位移」的验收条款;pin nanoid 只动一处。两条路也不冲突 —— 将来 postcss 自然浮到 8.5.26 时,它要的 ^3.3.17 正被现在解析出的 3.3.18 满足。

传入路径与 #6506 的记录一致并已独立复核:postcss@8.5.25nanoid: 3.3.16,改前在 pnpm-lock.yaml:14408(改后该边成为 nanoid: 3.3.18,行号 14409);改前 overrides 里确实没有任何 nanoid 条目。

OSV 门在锁文件上变红,因此对每一个 open PR 都生效,与各 PR 的改动内容无关。
本地以 osv-scanner v2.3.8(与 CI action 同版本)、同样的 `--lockfile=pnpm-lock.yaml`
参数复现:1387 个包,1 条 High(8.2)—— nanoid 3.3.16 命中
GHSA-2v37-7h3g-55p8 / CVE-2026-67213(自定义字母表在 size 为零时无限循环,
即拒绝服务),退出码 1。

公告带**两条**受影响区间:introduced:0 → fixed:3.3.17,以及
introduced:4.0.0 → fixed:5.1.6。此处只有第一条是活的:3.3.16 唯一由
postcss@8.5.25 间接引入(全锁文件仅一条 `nanoid:` 边),而四个 driver 直接声明的
nanoid ^6.0.0 高于第二条的修复线,本就不受影响。

上界按 AGENTS.md 与本块头部规则落在 target 之上的 **major 边界**(4.0.0),
⛔ 不写成 `<3.3.17` —— 那个形状会在 3.3.17 自己出公告那天当场失配
(undici 7.28.0 / brace-expansion 5.0.8 的活体标本,#4961 / #5032)。
`<4.0.0` 同时把 6.x 挡在选择器之外,正是它该待的地方。

^3.3.17 落在 postcss 自己声明的 ^3.3.16 区间内,所以这是往补丁线上的一次
dedupe,而不是把 postcss 顶过它支持的范围。

解析版本位移实测:1387 个 packages 键 + 1387 个 snapshots 键 + 746 条
importer 边,逐一比对,**只有 nanoid 3.3.16 → 3.3.18 一处**(^3.3.17 在 3.x
内浮到最新,即 npm 的 legacy dist-tag),其余零位移。改后复跑同一扫描:
No issues found,退出码 0,且 osv-scanner.toml 一字未动(仍是零豁免)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BDmDsu2575gDxeMCxXhDE3
@vercel

vercel Bot commented Aug 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 8, 2026 3:28am

Request Review

@github-actions github-actions Bot added size/s dependencies Pull requests that update a dependency file labels Aug 8, 2026
@hotlong hotlong changed the title fix(deps): nanoid 顶到 3.3.x 补丁线,清掉 GHSA-2v37-7h3g-55p8 (#6529) fix(deps): nanoid 顶到 3.3.x 补丁线,清掉 GHSA-2v37-7h3g-55p8 (#6506) Aug 8, 2026
@hotlong hotlong added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 8, 2026 — with Claude
@hotlong
hotlong marked this pull request as ready for review August 8, 2026 04:03
@hotlong
hotlong added this pull request to the merge queue Aug 8, 2026
Merged via the queue into main with commit 19f7586 Aug 8, 2026
29 of 30 checks passed
@hotlong
hotlong deleted the claude/issue-6529-nanoid-advisory branch August 8, 2026 04:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Validate Package Dependencies 在 main 上全仓变红:nanoid 3.3.16 命中 GHSA-2v37-7h3g-55p8(有 fix,缺 override)

2 participants