Files
iptvnator/docs/architecture/dependency-security-overrides.md
T
4grayandClaude Opus 5 e91a7cde7a 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>
2026-07-26 02:21:11 +02:00

75 lines
3.1 KiB
Markdown

# 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.