fix(web): pin transitive deps via pnpm overrides for security advisories#2522
fix(web): pin transitive deps via pnpm overrides for security advisories#2522
Conversation
Five Dependabot security advisories on web/pnpm-lock.yaml were stuck at "security_update_not_possible" because the transitive parents declare permissive ranges (e.g., ajv@8.18.0 wants fast-uri ^3.0.1) but pnpm's lockfile pinned the older vulnerable version. Dependabot can't rewrite transitive locks without a hint. Adding pnpm.overrides forces the resolved versions for the entire dep graph: - fast-uri ^3.1.2 (high — host confusion via percent-encoded authority) - fast-xml-builder ^1.1.7 (high — attribute-quote bypass + medium comment-regex) - esbuild ^0.27.3 (medium — dev-server CORS; range chosen to also satisfy astro@5.18.1's declared esbuild dep) - vite ^6.4.2 (medium — path traversal in optimized deps .map handling) - yaml ^2.8.3 (medium — stack overflow on deeply nested collections) Lockfile shrinks ~570 lines as duplicate versions consolidate into single canonical resolutions: - esbuild: was 0.21.5 + 0.25.12 + 0.27.7 → now only 0.27.7 - vite: was 5.4.21 + 6.4.2 → now only 6.4.2 - yaml: was 2.7.1 + 2.8.3 → now only 2.8.3 - fast-uri: 3.1.0 → 3.1.2 - fast-xml-builder: 1.1.5 → 1.2.0 Out of scope (separate PRs needed): - Astro XSS (fixed_in 6.1.6) — major version bump, requires build testing - Root package-lock.json fast-uri — different package manager (npm), separate dep graph Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Wheels Bot — Reviewer A
TL;DR: This PR correctly addresses five stuck Dependabot advisories by introducing pnpm.overrides in web/package.json, which is the right tool for this scenario. The approach is sound, the rationale is well-documented, and the net -570 line lockfile cleanup is a genuine improvement. One minor nit on the fast-xml-builder override range, and one observation on a vitefu peer-dep entry in the lockfile. Overall: approve with nits.
Correctness
fast-xml-builder override minimum is below the patched version
web/package.json, line 35:
"fast-xml-builder": "^1.1.7"The PR body lists the advisory as "fixed in 1.2.0", but the override floor is ^1.1.7 (>=1.1.7 <2.0.0). In practice pnpm resolves to 1.2.0 today because that is the highest published version in the range, and the lockfile confirms it. However, if the 1.1.x line ever receives a backport release (even a hypothetical 1.1.8), pnpm could resolve there instead of 1.2.0, reintroducing the vulnerability.
Suggested fix — align the minimum with the actual patched release:
"fast-xml-builder": "^1.2.0"The other four overrides (fast-uri@^3.1.2, esbuild@^0.27.3, vite@^6.4.2, yaml@^2.8.3) all pin to the patched floor or above it; fast-xml-builder is the odd one out.
Docs
vitefu peer-dep range in the packages: section
web/pnpm-lock.yaml, around the vitefu@1.1.3 entry under packages::
- vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
+ vite: ^6.4.2The packages: section is supposed to reflect what the published package itself declares as a peer dep. The narrowing from the broad disjunction to just ^6.4.2 is unusual — it either means vitefu@1.1.3 changed its own declaration upstream, or pnpm's override mechanism rewrote the metadata for resolution purposes. Either way it is worth verifying against the published vitefu@1.1.3 package.json on the registry to confirm this is correct lockfile output before merge. This does not block approval but should be confirmed.
Commits
Single commit, format fix(web): pin transitive deps via pnpm overrides for security advisories:
- type
fix— valid ✓ - scope
web— in the allowlist ✓ - subject not ALL-CAPS, under 100 chars ✓
All good.
Tests / Security
No CFML code changes; no Wheels test suite changes required. The dependency-only update is the correct scope. CI (web-deploy.yml) is the right gate here and is called out in the test plan. No secrets introduced. ✓
Wheels Bot — Reviewer B (round 1)A's review is solid overall — the main finding (fast-xml-builder floor mismatch) is correct and actionable, the commit message check is accurate, and A correctly scoped out CFML/Wheels test changes as unnecessary. One false positive on the vitefu observation, and a minor wording inconsistency in the verdict. SycophancyNone detected. A did not rubber-stamp the PR; they identified a specific, actionable correctness gap and raised a secondary observation for verification. A's GitHub review state is False positivesvitefu peer-dep range narrowing flagged as "unusual" — this is expected pnpm behavior. A's observation:
The diff at vitefu@1.1.3:
peerDependencies:
- vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
+ vite: ^6.4.2pnpm's override mechanism does exactly this by design: when a dependency is overridden, pnpm narrows the recorded peer dep range in Missed issuesNone of substance for this PR type. The change is purely JS dependency lockfile; there are no CFML, routing, or framework changes to audit. A covered all five advisory packages, checked the esbuild range reasoning, and noted the out-of-scope items (Astro XSS, root package-lock.json) correctly. One marginal note A could have made explicit: the fast-xml-builder advisory covers two CVEs (attribute-quote bypass and comment-regex bypass), both fixed in 1.2.0. A mentions 1.2.0 as the fixed version but does not state which CVEs are resolved by the floor bump — this is a presentation nit rather than a missed issue, since A's conclusion (bump to Verdict alignmentA's written conclusion is "approve with nits" but the submitted GitHub review state is |
Summary
Resolves five Dependabot
security_update_not_possiblefailures onweb/pnpm-lock.yamlby addingpnpm.overrides. Each advisory was stuck because the parent declares a permissive semver range that would allow the patched version, but the lockfile pinned the vulnerable version and Dependabot can't rewrite transitive locks without a hint.Advisories resolved
.maphandlingWhy pnpm.overrides (vs upgrading parents)
The transitive parents (ajv, fast-xml-parser, astro, etc.) all declare semver ranges that technically satisfy the patched versions. The actual problem is pnpm's lockfile preference — it kept the old resolutions.
pnpm.overridesis the standard pattern for this exact scenario: it tells pnpm to pick a specific version regardless of what the cached resolution previously chose.Constraint chosen for esbuild
^0.27.3(not^0.25.0as the advisory minimum) — this satisfies both:esbuild: ^0.27.3Using
^0.25.0would have violated astro's range and risked runtime issues.^0.27.3threads both.Lockfile cleanup
Net
-570 linesbecause duplicate version entries (e.g., esbuild was pinned at three different versions across the graph) collapse into single canonical resolutions. Smaller graph, less duplication, cleaner installs.Out of scope (will be separate PRs)
define:vars(fixed_in 6.1.6) — major version bump from 5.x → 6.x. Affects all five sites' direct deps. Needs build/visual testing before shipping. Tracking separately.package-lock.jsonfast-uri — that's the npm-managed graph for dev tooling (husky, commitlint, anthropic-ai/sdk, playwright, tsx). Different package manager, different fix.Test plan
gh run list --event dynamic --status failureno longer shows fast-uri / fast-xml-builder / esbuild / vite / yaml failures🤖 Generated with Claude Code