Skip to content

fix(repo): pin nanoid to 3.3.17 for GHSA-2v37-7h3g-55p8 - #6

Merged
evk-soft merged 1 commit into
mainfrom
fix/nanoid-advisory
Aug 8, 2026
Merged

fix(repo): pin nanoid to 3.3.17 for GHSA-2v37-7h3g-55p8#6
evk-soft merged 1 commit into
mainfrom
fix/nanoid-advisory

Conversation

@evk-soft

@evk-soft evk-soft commented Aug 8, 2026

Copy link
Copy Markdown
Owner

What lands and why

check-audit.mjs went from check-audit ok (0 advisories, 0 blocking) to a blocking failure between
two runs about an hour apart on 2026-08-08:

ADVISORY: high GHSA-2v37-7h3g-55p8 nanoid

nanoid < 3.3.17 loops indefinitely when a custom generator is called with size 0. CI runs
pnpm run check:supply-chain, so this blocked every pull request — main included.

Why it is fixed rather than ignored

The advisory reaches the tree only through vitest -> vite -> postcss:

nanoid@3.3.16
└─┬ postcss@8.5.25
  └─┬ vite@8.2.0
    └─┬ vitest@4.1.10  (devDependency of @evk-soft/ai-tooling)

So it is dev-only and can never be shipped: packages/ai-tooling declares only ajv,
json-canonicalize and jsonc-parser, and its files array carries no test tooling. Every finding
in pnpm audit --json reports dev: true.

It is fixed anyway. check-audit.mjs fails on any high or critical advisory by design, and adding
the first entry to an empty IGNORED_ADVISORIES list would spend the repository's one clean exception
record on a dependency that had a patched version available the same day.

The override pins an exact version, and that is the point

The first attempt used >=3.3.17 and resolved to nanoid@6.0.1 — a major jump across an API
postcss does not expect, adopted silently by a one-line override. It was caught by reading the
resulting lockfile, not by any check. The override now reads:

overrides:
  nanoid@<3.3.17: 3.3.17

3.3.18 exists, published 2026-08-07 16:41 UTC, and is still inside minimumReleaseAge: 4320;
3.3.17 was published 2026-08-03 10:39 UTC and cleared the threshold on 2026-08-06. The supply-chain
delay steering the choice of patch version is the second time it has done real work in this
repository.

How it was verified

Every command below exits 0 against the committed tree, after rm -rf node_modules and a clean
install — so the package counts are the honest ones and not inflated by orphans left in the virtual
store.

pnpm install --frozen-lockfile --ignore-scripts
pnpm check                    # 121 unit/package/security + 7 integration = 128 tests
pnpm run check:structure      # 5 workspaces no cycle; 37 source files no boundary escape
pnpm run check:supply-chain   # 0 advisories; 86 packages 0 licence conflicts
pnpm run changelog:check      # 0 fragments valid
node packages/ai-tooling/scripts/check-stage1-artifacts.mjs --phase 1 --tree
git diff --check

The lockfile now resolves a single nanoid@3.3.17, and the approved Phase 1 tree is untouched.

Deliberately not included

No changelog fragment. A dev-only dependency pin ships no behaviour change, and changelog.d/
stays dormant until Stage 1 Phase 5 completes.

The override is temporary and must be removed. Once vite ships a postcss that depends on a
patched nanoid, drop it. An override that outlives its cause silently pins a transitive dependency
forever, which is the failure mode the catalog exists to prevent. Recorded in PROGRESS.md.

check-audit.mjs went from "0 advisories" to a blocking failure between two runs
an hour apart: nanoid below 3.3.17 loops indefinitely when a custom generator is
called with size 0, rated high. CI runs check:supply-chain, so this blocked every
pull request, including main.

The advisory reaches the tree only through vitest -> vite -> postcss, so it is
dev-only and can never be shipped: packages/ai-tooling declares just ajv,
json-canonicalize and jsonc-parser, and its files array carries no test tooling.
It is fixed rather than ignored anyway. check-audit.mjs fails on any high
advisory by design, and adding the first entry to an empty IGNORED_ADVISORIES
list would spend the repository's one clean exception record on a dependency that
had a patched version available the same day.

The override pins exactly 3.3.17, and the exactness is the point. The first
attempt used >=3.3.17 and resolved to nanoid 6.0.1 -- a major jump across an API
postcss does not expect, adopted silently by a one-line override. It was caught
by reading the resulting lockfile, not by any check. 3.3.18 exists, published
2026-08-07, and is still inside minimumReleaseAge; 3.3.17 cleared it on
2026-08-06. The delay steering the choice of patch version is the second time it
has done real work here.

The override must be dropped once vite ships a postcss that depends on a patched
nanoid. An override that outlives its cause silently pins a transitive dependency
forever, which is the failure mode this repository's catalog exists to prevent.
@evk-soft
evk-soft merged commit 4293b30 into main Aug 8, 2026
3 checks passed
@evk-soft
evk-soft deleted the fix/nanoid-advisory branch August 8, 2026 15:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant