Closes the last three Dependabot alerts (4, 5 and 6 — all GHSA-82fw-gwwq-j7x9, path traversal / arbitrary file read via @vitest/mocker's redirect mock).
Why it has to be a major
There is no fix in the 3.x line. The advisory's patched versions are 4.1.11 and 5.0.0-rc.2 only, so 3.2.7 → 4.1.11 is the smallest move that clears it. Exposure was dev-only — no browser mode is configured and the server tests use tsx --test — but it is the only remaining open alert on the repo.
vite stays at 6.4.3: vitest 4 peers on ^6.0.0 || ^7.0.0 || ^8.0.0, so nothing needed to move with it. Nothing outside devDependencies changes. The lockfile drops vite-node, tinypool, tinyspy, cac, strip-literal and the old chai internals, and picks up obug and @standard-schema/spec.
The one failure, which was ours
compose-from-share expected two uploads and got three.
vitest 4 changed vi.spyOn to return the spy already installed on a method rather than wrapping it in a fresh one. That suite installs its spy in beforeEach and never restores it, so from 4.1.11 the call count is cumulative — the two uploads the test makes, plus the one from the test before it. The assertion had only been passing because each test happened to be handed a new spy; the leak was there all along.
Both suites now restore between tests, matching what the other five spying suites in web already do:
store/__tests__/compose-from-share.test.ts — the actual failure.
lib/__tests__/webpush.test.ts — the same leak, with no assertion close enough to have caught it. vi.spyOn(client, "call") was left mocked for the rest of the file.
No test expectations were changed to make anything pass.
Verification
npm run typecheck, npm test (1153 web tests across 113 files, plus 168 server tests) and npm run build all pass. npm audit reports 0 vulnerabilities.
Closes the last three Dependabot alerts (4, 5 and 6 — all `GHSA-82fw-gwwq-j7x9`, path traversal / arbitrary file read via `@vitest/mocker`'s redirect mock).
## Why it has to be a major
There is no fix in the 3.x line. The advisory's patched versions are 4.1.11 and 5.0.0-rc.2 only, so 3.2.7 → 4.1.11 is the smallest move that clears it. Exposure was dev-only — no browser mode is configured and the server tests use `tsx --test` — but it is the only remaining open alert on the repo.
`vite` stays at 6.4.3: vitest 4 peers on `^6.0.0 || ^7.0.0 || ^8.0.0`, so nothing needed to move with it. Nothing outside `devDependencies` changes. The lockfile drops `vite-node`, `tinypool`, `tinyspy`, `cac`, `strip-literal` and the old chai internals, and picks up `obug` and `@standard-schema/spec`.
## The one failure, which was ours
`compose-from-share` expected two uploads and got three.
vitest 4 changed `vi.spyOn` to return the spy already installed on a method rather than wrapping it in a fresh one. That suite installs its spy in `beforeEach` and never restores it, so from 4.1.11 the call count is cumulative — the two uploads the test makes, plus the one from the test before it. The assertion had only been passing because each test happened to be handed a new spy; the leak was there all along.
Both suites now restore between tests, matching what the other five spying suites in `web` already do:
- `store/__tests__/compose-from-share.test.ts` — the actual failure.
- `lib/__tests__/webpush.test.ts` — the same leak, with no assertion close enough to have caught it. `vi.spyOn(client, "call")` was left mocked for the rest of the file.
No test expectations were changed to make anything pass.
## Verification
`npm run typecheck`, `npm test` (1153 web tests across 113 files, plus 168 server tests) and `npm run build` all pass. `npm audit` reports 0 vulnerabilities.
**Merged** 2026-09-10 as coffey-labs/ihasmail@a2ae868f2824
<sub>Rebuilt from: git history, session transcript.</sub>
This repo is archived. You cannot comment on issues.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes the last three Dependabot alerts (4, 5 and 6 — all
GHSA-82fw-gwwq-j7x9, path traversal / arbitrary file read via@vitest/mocker's redirect mock).Why it has to be a major
There is no fix in the 3.x line. The advisory's patched versions are 4.1.11 and 5.0.0-rc.2 only, so 3.2.7 → 4.1.11 is the smallest move that clears it. Exposure was dev-only — no browser mode is configured and the server tests use
tsx --test— but it is the only remaining open alert on the repo.vitestays at 6.4.3: vitest 4 peers on^6.0.0 || ^7.0.0 || ^8.0.0, so nothing needed to move with it. Nothing outsidedevDependencieschanges. The lockfile dropsvite-node,tinypool,tinyspy,cac,strip-literaland the old chai internals, and picks upobugand@standard-schema/spec.The one failure, which was ours
compose-from-shareexpected two uploads and got three.vitest 4 changed
vi.spyOnto return the spy already installed on a method rather than wrapping it in a fresh one. That suite installs its spy inbeforeEachand never restores it, so from 4.1.11 the call count is cumulative — the two uploads the test makes, plus the one from the test before it. The assertion had only been passing because each test happened to be handed a new spy; the leak was there all along.Both suites now restore between tests, matching what the other five spying suites in
webalready do:store/__tests__/compose-from-share.test.ts— the actual failure.lib/__tests__/webpush.test.ts— the same leak, with no assertion close enough to have caught it.vi.spyOn(client, "call")was left mocked for the rest of the file.No test expectations were changed to make anything pass.
Verification
npm run typecheck,npm test(1153 web tests across 113 files, plus 168 server tests) andnpm run buildall pass.npm auditreports 0 vulnerabilities.Merged 2026-09-10 as coffey-labs/ihasmail@a2ae868f28
Rebuilt from: git history, session transcript.