You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
moment (maintenance mode; 2 files + the react-big-calendar localizer) → migrate to a maintained date lib when CalendarWidget is next reworked (the feat: good mobile view - Phase 2 - main application #118 mobile agenda view is the natural moment), not as standalone churn.
react-color 2.19.3 (unmaintained since ~2021; 2 files) → swap to @uiw/react-colorwhen the color picker is next touched.
ical-generator 10→11 (major; Node 22/24 only — fine on the new node:24-slim image; used only by the ICS export endpoint) → optional, take it with a test pass or leave it.
Suggested standing policy
Act only when: (a) npm audit flags anything, (b) a package on the external-input list above falls a major behind, or (c) a dep actually used in the app goes officially EOL/deprecated. Everything else may drift freely. That replaces this issue's blanket ask — recommend keeping wontfix on the general bump (or closing once Tier 1 lands).
Update 2026-08-12 — audit trigger has fired
Trigger (a) of the standing policy above (npm audit flags something) is now
met: 5 HIGH advisories on server/. Investigated while evaluating #135
(an automated bot PR, closed unmerged — see the trap below). Findings recorded
here so the next person doesn't have to re-derive them.
Host confusion via backslash. Transitive (Fastify).
⚠️ The @fastify/static v10 trap (this is what killed #135)
v10.0.0 changed the setHeaders callback to receive a FastifyReply
instead of the raw Node response. Two of our three registrations in server/index.js (the /Uploads/ and /Uploads/users/ roots, ~lines 477 and
489) call res.setHeader(...), which does not exist on Reply.
Failure mode is nastier than a 500: the TypeError is uncaught, so the
backend process dies on the first request to /Uploads/* — i.e. seconds
after any dashboard load, since every photo, sound, and avatar goes through
that path. Reproduced both in isolation (Fastify 5.10.0 + static 10.1.3) and
by running our suite against #135's lockfile (2 failures, ECONNRESET).
The migration is two lines per registration:
// before (v9) // after (v10)
setHeaders: (res,path)=>{setHeaders: (reply)=>{res.setHeader('Cache-Control', ...);reply.header('Cache-Control', ...);}}
The /widgets/ registration passes no setHeaders and is unaffected.
Verified: with that change, server is 114/114 green on static 10.1.2.
Verified compatibility facts (so we don't re-litigate the major bump)
Fastify 5 is fine. v10 declares no peerDependencies, installs against fastify@5.10.0 with no resolution conflict, and boots cleanly. setHeaders
is the only breaking change that touches our code.
No 9.x backport exists. First patched version is 10.1.1; the whole 9.x
line (incl. 9.2.0 / 9.3.0) is in the affected range. Staying on 9 means
carrying a permanent HIGH finding and a recurring stream of bot PRs.
Target ^10.1.3, not 10.1.1 — the moderate CVE-2026-7120 affects ≤10.1.1.
Priority: real, but not urgent
CVE-2026-15074 is a route-guard bypass, not a root escape: non-leading ../ / %2E%2E segments match the static catch-all instead of a guarded
route. It cannot read outside the static root (/Uploads/../package.json →
404 on v10, and @fastify/send's own traversal check still runs). data/,
the SQLite DB, and the encryption key were never reachable this way.
We have exactly one preHandler hook (a request logger) and no route-based
guards on any path under /Uploads/ or /widgets/ — everything the static
plugin serves is unauthenticated by design. So there is nothing to bypass and the CVE is not exploitable in our configuration. Do the upgrade to clear
scanners and stop the bot-PR churn, not because there's live risk.
Related gap: CI does not run on PRs
ci-tests.yml triggers only on push, so fork PRs get zero checks — #135
showed as "mergeable / CLEAN" with nothing run, even though our own suite
catches its breakage. Adding pull_request to that trigger would have caught
it automatically, and is worth doing before the next contributor PR.
Watch-list (act on trigger, not on schedule)
moment(maintenance mode; 2 files + the react-big-calendar localizer) → migrate to a maintained date lib when CalendarWidget is next reworked (the feat: good mobile view - Phase 2 - main application #118 mobile agenda view is the natural moment), not as standalone churn.react-color2.19.3 (unmaintained since ~2021; 2 files) → swap to@uiw/react-colorwhen the color picker is next touched.ical-generator10→11 (major; Node 22/24 only — fine on the new node:24-slim image; used only by the ICS export endpoint) → optional, take it with a test pass or leave it.Suggested standing policy
Act only when: (a)
npm auditflags anything, (b) a package on the external-input list above falls a major behind, or (c) a dep actually used in the app goes officially EOL/deprecated. Everything else may drift freely. That replaces this issue's blanket ask — recommend keepingwontfixon the general bump (or closing once Tier 1 lands).Update 2026-08-12 — audit trigger has fired
Trigger (a) of the standing policy above (
npm auditflags something) is nowmet: 5 HIGH advisories on
server/. Investigated while evaluating #135(an automated bot PR, closed unmerged — see the trap below). Findings recorded
here so the next person doesn't have to re-derive them.
The queue (one deliberate pass, not five bot PRs)
@fastify/static^10.1.3fast-xml-parsernpm audit fixis a no-op. Pin looks deliberate (CalDAV CDATA work in #106) — re-run the CalDAV tests.find-my-wayfastifybrace-expansionfast-uri@fastify/staticv10 trap (this is what killed #135)v10.0.0 changed the
setHeaderscallback to receive aFastifyReplyinstead of the raw Node response. Two of our three registrations in
server/index.js(the/Uploads/and/Uploads/users/roots, ~lines 477 and489) call
res.setHeader(...), which does not exist onReply.Failure mode is nastier than a 500: the
TypeErroris uncaught, so thebackend process dies on the first request to
/Uploads/*— i.e. secondsafter any dashboard load, since every photo, sound, and avatar goes through
that path. Reproduced both in isolation (Fastify 5.10.0 + static 10.1.3) and
by running our suite against #135's lockfile (2 failures,
ECONNRESET).The migration is two lines per registration:
The
/widgets/registration passes nosetHeadersand is unaffected.Verified: with that change,
serveris 114/114 green on static 10.1.2.Verified compatibility facts (so we don't re-litigate the major bump)
peerDependencies, installs againstfastify@5.10.0with no resolution conflict, and boots cleanly.setHeadersis the only breaking change that touches our code.
line (incl. 9.2.0 / 9.3.0) is in the affected range. Staying on 9 means
carrying a permanent HIGH finding and a recurring stream of bot PRs.
^10.1.3, not 10.1.1 — the moderate CVE-2026-7120 affects ≤10.1.1.Priority: real, but not urgent
CVE-2026-15074 is a route-guard bypass, not a root escape: non-leading
..//%2E%2Esegments match the static catch-all instead of a guardedroute. It cannot read outside the static root (
/Uploads/../package.json→404 on v10, and
@fastify/send's own traversal check still runs).data/,the SQLite DB, and the encryption key were never reachable this way.
We have exactly one
preHandlerhook (a request logger) and no route-basedguards on any path under
/Uploads/or/widgets/— everything the staticplugin serves is unauthenticated by design. So there is nothing to bypass and
the CVE is not exploitable in our configuration. Do the upgrade to clear
scanners and stop the bot-PR churn, not because there's live risk.
Related gap: CI does not run on PRs
ci-tests.ymltriggers only onpush, so fork PRs get zero checks — #135showed as "mergeable / CLEAN" with nothing run, even though our own suite
catches its breakage. Adding
pull_requestto that trigger would have caughtit automatically, and is worth doing before the next contributor PR.