Skip to content

Frontend: resolve pnpm audit findings, 30 vulnerabilities - #1374

Merged
gusthoff merged 8 commits into
AdaCore:mainfrom
gusthoff:dev/topic/infrastructure/pnpm/security-audit-fixes/2026-07-24
Jul 24, 2026
Merged

Frontend: resolve pnpm audit findings, 30 vulnerabilities#1374
gusthoff merged 8 commits into
AdaCore:mainfrom
gusthoff:dev/topic/infrastructure/pnpm/security-audit-fixes/2026-07-24

Conversation

@gusthoff

@gusthoff gusthoff commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • pnpm audit on frontend/ reported 30 findings (1 critical, 17 high, 9
    moderate, 3 low) across the dependency tree. This branch brings that to
    0 vulnerabilities, verified after every commit, without upgrading any
    direct dependency's declared version.
  • Two independent root causes accounted for most of it:
    • sass-lint/sass-lint-webpack — unmaintained since 2018, unreferenced
      by any webpack config, package.json script, or CI workflow. Confirmed
      dead code and removed outright (drops the tree from 984 to 864 packages).
    • package.json carried an 11-entry Yarn-era resolutions block left
      over from the pre-pnpm migration. pnpm does not read a bare
      resolutions key — its own override mechanism is overrides: in
      pnpm-workspace.yaml — so none of those pins had been enforced since
      the migration, silently exposing findings the original pins were meant
      to prevent (confirmed by cross-referencing the pins against what
      pnpm audit was still flagging).
  • Remaining findings (brace-expansion, js-yaml, immutable, mocha's
    diff, undici via jsdom, svgo) were each fixed with a scoped
    pnpm-workspace.yaml override, chosen to stay inside the version range
    the actual consuming package already declares as compatible (e.g.
    undici: ^7.28.0 sits inside jsdom's own ^7.25.0) — not an arbitrary
    version jump. Where only one code path was vulnerable (diff via mocha
    vs. ts-node's unrelated, unaffected copy), the override was scoped with
    parent>child syntax instead of applying tree-wide.

Test plan

  • pnpm audit — 0 vulnerabilities (down from 30)
  • pnpm install --frozen-lockfile — lockfile is self-consistent
  • pnpm run tsc — clean after every commit
  • pnpm run cover (exact CI step from typescript-tests.js.yml) — 126
    passing, coverage unchanged
  • make cleanall webpack-production (exact CI step from
    sphinx-content-tests.js.yml / sphinx-books-tests.js.yml) — cold
    rebuild, identical bundle size and warnings to before

gusthoff and others added 8 commits July 24, 2026 19:23
Neither package is referenced by any webpack config (webpack.common.cjs,
webpack.dev.cjs, webpack.prod.cjs), any package.json script, or any
.github/workflows/*.yml file — the .sass-lint.yml config they would have
read is likewise orphaned. sass-lint itself has been unmaintained since
2018 and pulls in several vulnerable transitive dependencies (minimist,
shelljs, merge, ajv, an old vendored minimatch), including the only
critical-severity finding in `pnpm audit`. Removing the pair drops the
frontend dependency tree from 984 to 864 packages and clears 12 of the
30 pnpm audit findings (1 critical, 2 high, 3 moderate) with no build or
test impact: `pnpm run tsc`, `pnpm exec mocha`, and `pnpm run production`
all still pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
package.json carried an eleven-entry "resolutions" block (minimist, acorn,
is-svg, ssri, whatwg-url, lodash, serialize-javascript, globule/minimatch,
follow-redirects, picomatch, uuid) left over from before the Yarn-to-pnpm
migration. pnpm does not read a bare "resolutions" key at all — its
override mechanism is a "pnpm.overrides" field in package.json or an
"overrides" key in pnpm-workspace.yaml — so none of these pins have been
enforced since the migration. `pnpm audit` confirms this: it still flagged
several of the exact packages the pins were meant to fix (addressed
separately by removing sass-lint in the previous commit).

Checked each of the eleven entries against the current pnpm-lock.yaml
before deciding what to keep:
- is-svg, ssri, follow-redirects, and uuid no longer appear anywhere in
  the dependency tree; later dependency upgrades already eliminated the
  paths that used to pull them in.
- acorn, whatwg-url, lodash, and picomatch already resolve to versions at
  or above the old pin on their own, with no override needed.
- serialize-javascript was the one pin still doing real work: the tree
  carried two copies, a safe 7.0.5 pulled in by newer tooling and a
  vulnerable 6.0.2 pulled in by mocha (CVE-worthy RCE via RegExp.flags /
  Date.prototype.toISOString, plus a separate DoS advisory). This is
  restored as a proper pnpm-workspace.yaml override, which dedupes the
  tree down to the single safe copy.

`pnpm exec mocha` (126 passing) is unaffected.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
pnpm audit flagged the same brace-expansion DoS advisory
(GHSA-3jxr-9vmj-r5cp, exponential-time expansion of consecutive
non-expanding {} groups) three times, once per incompatible major
version present in the tree: 1.1.15 (via clean-webpack-plugin's del
dependency), 2.1.1 (via mocha's own minimatch/glob), and 5.0.6 (via
@babel/cli and @typescript-eslint's minimatch). Each copy sat exactly one
patch below its own safe threshold.

brace-expansion's public API (a single function expanding {a,b,c}-style
glob patterns into an array) has stayed stable across these majors, so a
single tree-wide override to the latest safe release collapses all three
copies into one instead of needing three parent-path-scoped overrides.
Verified this doesn't break anything that resolves glob patterns via
minimatch: `pnpm run tsc`, `pnpm exec mocha` (126 passing), `pnpm run
production`, and `pnpm run eslint` (276 pre-existing problems, unchanged
count) all behave identically to before the override.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
pnpm audit flagged js-yaml 4.1.1 (deduped to a single copy shared by
mocha, webpack-cli, and cosmiconfig) for two quadratic-complexity DoS
advisories in merge-key/alias handling: GHSA-52cp-r559-cp3m (fixed at
>=4.3.0) and GHSA-h67p-54hq-rp68 (fixed at >=4.1.2). Since pnpm already
resolves the whole tree to one js-yaml version, a single override
clears both findings without touching any direct dependency.

Verified: `pnpm run tsc`, `pnpm run test` (126 passing), and `pnpm run
production` all behave identically to before the override.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
pnpm audit flagged immutable 5.1.6 (pulled in solely by sass's internal
use of the Dart-to-JS embedded compiler protocol, via sass-loader) for
two high-severity DoS advisories: a 32-bit trie overflow in List
(GHSA-v56q-mh7h-f735) and a hash-collision complexity blowup in
Map/Set (GHSA-xvcm-6775-5m9r), both fixed at >=5.1.8.

sass's own package.json already declares "immutable": "^5.1.5", so
overriding to ^5.1.8 stays inside the range sass itself considers
compatible rather than forcing an incompatible version on it.

Verified: `pnpm run tsc`, `pnpm run test` (126 passing), and `pnpm run
production` all behave identically to before the override.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
pnpm audit flagged jsdiff 7.0.0 for a DoS in parsePatch/applyPatch
(GHSA-73rr-hh4g-fpgx, vulnerable >=6.0.0 <8.0.3). The tree carries two
copies of diff: 4.0.4 via ts-node (below the vulnerable range, left
alone) and 7.0.0 via mocha's own dependency declaration, which mocha
11.7.6 (already the latest release) still pins to ^7.0.0. Scoped the
override to mocha>diff specifically, so ts-node's unrelated copy isn't
forced to change.

Verified: `pnpm run tsc` and `pnpm run test` (126 passing, including
mocha's own diff-based assertion-failure output) are unaffected.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
pnpm audit flagged undici 7.26.0 (pulled in by jsdom/jsdom-global,
used to build the DOM environment for the mocha test suite) for seven
advisories at various severities: a TLS certificate validation bypass
and cross-origin request routing issue via SOCKS5 proxy reuse (both
high), a WebSocket DoS via fragment count bypass (high), Set-Cookie
header injection and cross-user cache disclosure (moderate), and a
keep-alive queue-poisoning issue plus a SameSite downgrade (low). All
are fixed at >=7.28.0.

jsdom is already at its latest release (29.1.1) and its own
package.json already declares "undici": "^7.25.0", so ^7.28.0 stays
inside the range jsdom itself considers compatible.

Verified: `pnpm run tsc`, `pnpm run test` (126 passing, exercising the
jsdom-based DOM environment throughout), and `pnpm run production` are
all unaffected.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
pnpm audit flagged svgo 4.0.1 (pulled in via css-minimizer-webpack-plugin
-> cssnano -> cssnano-preset-default -> postcss-svgo, part of the
production CSS minification pipeline) for GHSA-2p49-hgcm-8545: the
removeScripts plugin leaves some executable scripts intact instead of
stripping them, fixed at >=4.0.2.

postcss-svgo's own package.json already declares "svgo": "^4.0.1", so
^4.0.2 stays inside the range postcss-svgo itself considers compatible.

This was the last remaining pnpm audit finding: `pnpm audit` now
reports 0 vulnerabilities (down from 30 at the start of this branch).

Verified: `pnpm run tsc`, `pnpm run test` (126 passing), and `pnpm run
production` (identical output size, same pre-existing size-limit
warnings) are all unaffected.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@gusthoff
gusthoff merged commit bb3da33 into AdaCore:main Jul 24, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant