fix(deps): patch transitive runtime CVEs via pnpm overrides (#1258)

Closes 13 runtime-scope Dependabot advisories that Dependabot cannot fix itself:
every vulnerable package here is transitive, so the bot has no lever until each
parent publishes a release widening its own pin.

Overrides added (pinned-source form, matching existing convention):

- @xmldom/xmldom 0.8.11 -> 0.8.13  (5 high) via video.js -> mpd-parser
- fast-uri       3.1.0  -> 3.1.4   (4 high) via electron-conf -> ajv
- js-yaml        4.1.1  -> 4.3.0   (2)      via electron-updater
- form-data      4.0.5  -> 4.0.6   (1 high) via axios
- ajv            8.17.1 -> 8.18.0  (1)      via electron-conf

Every target stays inside its parent's declared semver range. For xmldom,
fast-uri and js-yaml the newest published version is outside that range
(0.9.x / 4.x / 5.x), so "latest" would have broken them; the new doc
records that constraint.

Deliberately excluded: axios and uuid are direct deps already covered by open
Dependabot PRs (#1251, #1252). undici is labelled runtime scope but every path
to it is build tooling (electron -> @electron/get, @angular/build,
@module-federation/dts-plugin) and it is not in the packaged app.

Reachability: xmldom arrives via video.js -> VHS -> mpd-parser, but the app
routes every .mpd to Shaka, which uses its own DASH parser, so that one is
defence in depth. The genuinely reachable one is js-yaml, which
electron-updater uses to parse latest.yml from releases.

Adds docs/architecture/dependency-security-overrides.md and a .changes note.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Opus 5 authored and GitHub committed 2026-07-26 02:21:11 +02:00
1 parent 3032cfa88d
commit e91a7cde7a
4 files changed
+137 -52

No files matched your search

@@ -0,0 +1,8 @@
---
type: internal
area: deps
---
Patched five vulnerable transitive dependencies that ship with the app —
including the YAML parser `electron-updater` uses to read update manifests, and
the HTTP form encoder behind portal requests. No behaviour change.
@@ -0,0 +1,74 @@
# Dependency Security Overrides
How transitive CVEs are patched in this repo, and the constraint that makes
"just bump to latest" the wrong move.
## Why overrides exist
Dependabot can only bump packages we declare ourselves. When the vulnerable
package is transitive — pulled in by `video.js`, `electron-updater`,
`electron-conf`, `axios` — the bot has no lever: it would have to wait for the
parent to publish a release that widens its own pin. Until then the alert stays
open regardless of how many bot PRs land.
`pnpm.overrides` in the root `package.json` is that lever. Every entry uses the
pinned-source form so an override only rewrites the exact resolution it was
written for, and goes stale visibly instead of silently re-targeting a future
version:
```json
"@xmldom/xmldom@0.8.11": "0.8.13"
```
## The semver ceiling
**An override must stay inside the range its parent declares.** pnpm applies
overrides without re-checking the parent's range, so an out-of-range target
installs cleanly and then fails at runtime or under load, not at install time.
For three of the five current security overrides, the newest published version
is _outside_ the parent's range. Taking "latest" would break them:
| Override | Pinned to | Parent range | Latest on npm |
| ---------------- | --------- | --------------------------------------- | ------------- |
| `@xmldom/xmldom` | 0.8.13 | `mpd-parser` `^0.8.3`, `plist` `^0.8.8` | 0.9.x ❌ |
| `fast-uri` | 3.1.4 | `ajv` `^3.0.1` | 4.x ❌ |
| `js-yaml` | 4.3.0 | `electron-updater` `^4.1.0` | 5.x ❌ |
| `form-data` | 4.0.6 | `axios` `^4.0.5` | 4.0.6 ✅ |
| `ajv` | 8.18.0 | `electron-conf` `^8.13.0` | 8.20.0 ✅ |
Before changing any of these, check the parent's declared range first:
```bash
npm view <parent>@<version> dependencies --json
```
## Verifying an override actually applied
Grepping `pnpm-lock.yaml` for the old version still finds it, but that hit is
not a leftover package block — pnpm removes those once nothing resolves to them.
It is the override's own selector key, echoed in the `overrides:` block at the
top of the lockfile:
```yaml
overrides:
'@xmldom/xmldom@0.8.11': 0.8.13
```
So a bare grep proves only that the override is declared, never that it took
effect. Resolve the real path on disk instead:
```bash
node -e "console.log(require('./node_modules/.pnpm/mpd-parser@1.3.1/node_modules/@xmldom/xmldom/package.json').version)"
```
## What is deliberately not overridden
`undici` carries open alerts flagged `runtime` scope, but every path to it is
build tooling — `electron` → `@electron/get`, `@angular/build`, and
`@module-federation/dts-plugin`. It is not in the packaged app. The `runtime`
label is a Dependabot classification artifact, not a shipped-code claim. Bumping
it inside the Angular/Nx toolchain risks the build for no runtime benefit.
When triaging, confirm scope from the dependency graph rather than trusting the
alert's `scope` field.
+5
View File
@@ -218,16 +218,21 @@
"pnpm": {
"overrides": {
"@hono/node-server@1.19.9": "1.19.14",
"@xmldom/xmldom@0.8.11": "0.8.13",
"ajv@6.12.6": "6.14.0",
"ajv@8.17.1": "8.18.0",
"brace-expansion@1.1.12": "1.1.13",
"defu@6.1.4": "6.1.6",
"devalue@5.6.2": "5.6.4",
"express-rate-limit@8.2.1": "8.3.0",
"fast-uri@3.1.0": "3.1.4",
"flatted@3.3.3": "3.4.2",
"follow-redirects@1.15.11": "1.16.0",
"form-data@4.0.5": "4.0.6",
"h3@1.15.5": "1.15.10",
"hono@4.12.0": "4.12.14",
"immutable@5.1.4": "5.1.5",
"js-yaml@4.1.1": "4.3.0",
"lodash-es@4.17.22": "4.18.1",
"node-abi@3.85.0": "3.92.0",
"node-forge@1.3.3": "1.4.0",
+50 -52
View File
@@ -6,16 +6,21 @@ settings:
overrides:
'@hono/node-server@1.19.9': 1.19.14
'@xmldom/xmldom@0.8.11': 0.8.13
ajv@6.12.6: 6.14.0
ajv@8.17.1: 8.18.0
brace-expansion@1.1.12: 1.1.13
defu@6.1.4: 6.1.6
devalue@5.6.2: 5.6.4
express-rate-limit@8.2.1: 8.3.0
fast-uri@3.1.0: 3.1.4
flatted@3.3.3: 3.4.2
follow-redirects@1.15.11: 1.16.0
form-data@4.0.5: 4.0.6
h3@1.15.5: 1.15.10
hono@4.12.0: 4.12.14
immutable@5.1.4: 5.1.5
js-yaml@4.1.1: 4.3.0
lodash-es@4.17.22: 4.18.1
node-abi@3.85.0: 3.92.0
node-forge@1.3.3: 1.4.0
@@ -4712,10 +4717,9 @@ packages:
'@webassemblyjs/wast-printer@1.14.1':
resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==}
'@xmldom/xmldom@0.8.11':
resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==}
'@xmldom/xmldom@0.8.13':
resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==}
engines: {node: '>=10.0.0'}
deprecated: this version has critical issues, please update to the latest version
'@xtuc/ieee754@1.2.0':
resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==}
@@ -4806,7 +4810,7 @@ packages:
ajv-formats@2.1.1:
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
peerDependencies:
ajv: ^8.0.0
ajv: 8.18.0
peerDependenciesMeta:
ajv:
optional: true
@@ -4814,7 +4818,7 @@ packages:
ajv-formats@3.0.1:
resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==}
peerDependencies:
ajv: ^8.0.0
ajv: 8.18.0
peerDependenciesMeta:
ajv:
optional: true
@@ -4827,14 +4831,11 @@ packages:
ajv-keywords@5.1.0:
resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==}
peerDependencies:
ajv: ^8.8.2
ajv: 8.18.0
ajv@6.14.0:
resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==}
ajv@8.17.1:
resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
ajv@8.18.0:
resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==}
@@ -6498,8 +6499,8 @@ packages:
fast-levenshtein@2.0.6:
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
fast-uri@3.1.0:
resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==}
fast-uri@3.1.4:
resolution: {integrity: sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==}
fastq@1.20.1:
resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==}
@@ -6620,8 +6621,8 @@ packages:
typescript: '>3.6.0'
webpack: ^5.11.0
form-data@4.0.5:
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
form-data@4.0.6:
resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==}
engines: {node: '>= 6'}
forwarded@0.2.0:
@@ -6871,6 +6872,10 @@ packages:
resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==}
engines: {node: '>= 0.4'}
hasown@2.0.4:
resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==}
engines: {node: '>= 0.4'}
hast-util-from-html@2.0.3:
resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==}
@@ -7608,8 +7613,8 @@ packages:
resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==}
hasBin: true
js-yaml@4.1.1:
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
js-yaml@4.3.0:
resolution: {integrity: sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==}
hasBin: true
jsdom@26.1.0:
@@ -11278,8 +11283,8 @@ snapshots:
'@angular-devkit/core@21.1.4(chokidar@5.0.0)':
dependencies:
ajv: 8.17.1
ajv-formats: 3.0.1(ajv@8.17.1)
ajv: 8.18.0
ajv-formats: 3.0.1(ajv@8.18.0)
jsonc-parser: 3.3.1
picomatch: 4.0.3
rxjs: 7.8.2
@@ -11595,7 +11600,7 @@ snapshots:
hast-util-from-html: 2.0.3
hast-util-to-text: 4.0.2
import-meta-resolve: 4.2.0
js-yaml: 4.1.1
js-yaml: 4.3.0
mdast-util-definitions: 6.0.0
rehype-raw: 7.0.0
rehype-stringify: 10.0.1
@@ -11621,7 +11626,7 @@ snapshots:
hast-util-from-html: 2.0.3
hast-util-to-text: 4.0.2
import-meta-resolve: 4.2.0
js-yaml: 4.1.1
js-yaml: 4.3.0
mdast-util-definitions: 6.0.0
rehype-raw: 7.0.0
rehype-stringify: 10.0.1
@@ -13272,7 +13277,7 @@ snapshots:
globals: 14.0.0
ignore: 5.3.2
import-fresh: 3.3.1
js-yaml: 4.1.1
js-yaml: 4.3.0
minimatch: 3.1.2
strip-json-comments: 3.1.1
transitivePeerDependencies:
@@ -16104,7 +16109,7 @@ snapshots:
'@webassemblyjs/ast': 1.14.1
'@xtuc/long': 4.2.2
'@xmldom/xmldom@0.8.11': {}
'@xmldom/xmldom@0.8.13': {}
'@xtuc/ieee754@1.2.0': {}
@@ -16190,10 +16195,6 @@ snapshots:
optionalDependencies:
ajv: 8.18.0
ajv-formats@3.0.1(ajv@8.17.1):
optionalDependencies:
ajv: 8.17.1
ajv-formats@3.0.1(ajv@8.18.0):
optionalDependencies:
ajv: 8.18.0
@@ -16214,17 +16215,10 @@ snapshots:
json-schema-traverse: 0.4.1
uri-js: 4.4.1
ajv@8.17.1:
dependencies:
fast-deep-equal: 3.1.3
fast-uri: 3.1.0
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
ajv@8.18.0:
dependencies:
fast-deep-equal: 3.1.3
fast-uri: 3.1.0
fast-uri: 3.1.4
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
@@ -16335,7 +16329,7 @@ snapshots:
hosted-git-info: 4.1.0
is-ci: 3.0.1
isbinaryfile: 5.0.7
js-yaml: 4.1.1
js-yaml: 4.3.0
json5: 2.2.3
lazy-val: 1.0.5
minimatch: 10.1.1
@@ -16460,7 +16454,7 @@ snapshots:
html-escaper: 3.0.3
http-cache-semantics: 4.2.0
import-meta-resolve: 4.2.0
js-yaml: 4.1.1
js-yaml: 4.3.0
magic-string: 0.30.21
magicast: 0.5.2
mrmime: 2.0.1
@@ -16555,7 +16549,7 @@ snapshots:
axios@1.15.0:
dependencies:
follow-redirects: 1.16.0(debug@4.4.3)
form-data: 4.0.5
form-data: 4.0.6
proxy-from-env: 2.1.0
transitivePeerDependencies:
- debug
@@ -16563,7 +16557,7 @@ snapshots:
axios@1.16.0:
dependencies:
follow-redirects: 1.16.0(debug@4.4.3)
form-data: 4.0.5
form-data: 4.0.6
proxy-from-env: 2.1.0
transitivePeerDependencies:
- debug
@@ -16894,7 +16888,7 @@ snapshots:
http-proxy-agent: 7.0.2
https-proxy-agent: 7.0.6
is-ci: 3.0.1
js-yaml: 4.1.1
js-yaml: 4.3.0
sanitize-filename: 1.6.3
source-map-support: 0.5.21
stat-mode: 1.0.0
@@ -17269,7 +17263,7 @@ snapshots:
cosmiconfig@8.3.6(typescript@5.9.3):
dependencies:
import-fresh: 3.3.1
js-yaml: 4.1.1
js-yaml: 4.3.0
parse-json: 5.2.0
path-type: 4.0.0
optionalDependencies:
@@ -17279,7 +17273,7 @@ snapshots:
dependencies:
env-paths: 2.2.1
import-fresh: 3.3.1
js-yaml: 4.1.1
js-yaml: 4.3.0
parse-json: 5.2.0
optionalDependencies:
typescript: 5.9.3
@@ -17581,7 +17575,7 @@ snapshots:
builder-util-runtime: 9.3.1
fs-extra: 10.1.0
iconv-lite: 0.6.3
js-yaml: 4.1.1
js-yaml: 4.3.0
optionalDependencies:
dmg-license: 1.0.11
transitivePeerDependencies:
@@ -17702,7 +17696,7 @@ snapshots:
electron-conf@1.3.0(electron@41.7.2):
dependencies:
ajv: 8.17.1
ajv: 8.18.0
electron: 41.7.2
electron-playwright-helpers@1.8.2:
@@ -17715,7 +17709,7 @@ snapshots:
builder-util: 26.0.11
builder-util-runtime: 9.3.1
chalk: 4.1.2
form-data: 4.0.5
form-data: 4.0.6
fs-extra: 10.1.0
lazy-val: 1.0.5
mime: 2.6.0
@@ -17730,7 +17724,7 @@ snapshots:
dependencies:
builder-util-runtime: 9.7.0
fs-extra: 10.1.0
js-yaml: 4.1.1
js-yaml: 4.3.0
lazy-val: 1.0.5
lodash.escaperegexp: 4.1.2
lodash.isequal: 4.5.0
@@ -18379,7 +18373,7 @@ snapshots:
fast-levenshtein@2.0.6: {}
fast-uri@3.1.0: {}
fast-uri@3.1.4: {}
fastq@1.20.1:
dependencies:
@@ -18520,12 +18514,12 @@ snapshots:
typescript: 5.9.3
webpack: 5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.28.1)
form-data@4.0.5:
form-data@4.0.6:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
es-set-tostringtag: 2.1.0
hasown: 2.0.3
hasown: 2.0.4
mime-types: 2.1.35
forwarded@0.2.0: {}
@@ -18806,6 +18800,10 @@ snapshots:
dependencies:
function-bind: 1.1.2
hasown@2.0.4:
dependencies:
function-bind: 1.1.2
hast-util-from-html@2.0.3:
dependencies:
'@types/hast': 3.0.4
@@ -19832,7 +19830,7 @@ snapshots:
argparse: 1.0.10
esprima: 4.0.1
js-yaml@4.1.1:
js-yaml@4.3.0:
dependencies:
argparse: 2.0.1
@@ -20786,14 +20784,14 @@ snapshots:
dependencies:
'@babel/runtime': 7.28.4
'@videojs/vhs-utils': 3.0.5
'@xmldom/xmldom': 0.8.11
'@xmldom/xmldom': 0.8.13
global: 4.4.0
mpd-parser@1.3.1:
dependencies:
'@babel/runtime': 7.28.4
'@videojs/vhs-utils': 4.1.1
'@xmldom/xmldom': 0.8.11
'@xmldom/xmldom': 0.8.13
global: 4.4.0
mpegts.js@1.8.0:
@@ -21098,7 +21096,7 @@ snapshots:
figures: 3.2.0
flat: 5.0.2
follow-redirects: 1.16.0(debug@4.4.3)
form-data: 4.0.5
form-data: 4.0.6
fs-constants: 1.0.0
function-bind: 1.1.2
get-caller-file: 2.0.5
@@ -21552,7 +21550,7 @@ snapshots:
plist@3.1.0:
dependencies:
'@xmldom/xmldom': 0.8.11
'@xmldom/xmldom': 0.8.13
base64-js: 1.5.1
xmlbuilder: 15.1.1