Skip to content

Status note (2026-09-25): Dependency snapshot from September 2026. Package versions and upgrade advice are date-bound; verify installed manifests and current package documentation before acting.

Dependency Audit — September 2026 ​

TL;DR: dependency snapshot for backend and frontend from September 2026. Date-bound upgrade advice — verify installed manifests and current package docs before acting on it.

Investigation only. No package.json, lockfile, source, or config files were modified. Authoritative state: Bloxclips-backend@dev (01ec072) and BloxClips-frontend@dev (64bc449), both clean checkouts. Latest-stable versions resolved via npm view on 2026-09-21. Local runtime node v22.19.0 / npm 11.13.0.

Executive summary ​

Backend: healthy, slightly stale in safe places. Prisma family is on the latest stable line (7.10.0; the latest tag for the prisma CLI currently points at an 8.0.0-rc, so "newer" here means prerelease — stay put). Express 5 stack is current. The real action is a set of in-range lockfile refreshes that fix real advisories (axios prototype pollution, qs DoS, ip-address SSRF bypass, resend's svix/uuid chain) — no package.json edits needed for most of them because caret/override ranges already allow the fixed versions; the lockfile is just pinned to vulnerable copies. Whop invoice pin (1.0.14 alias) is deliberate and must stay. Three packages look unused (@noble/ciphers, date-fns, @types/ws).

Frontend: healthy and current where it matters. Next 16.3.3 is one patch behind latest stable (16.3.5); React 19 one minor behind (19.2.1 vs 19.3.0); Tailwind v4 one minor behind. All upgradable in low-risk batches. The @dnd-kit/* trio (core/sortable/utilities) has zero imports anywhere — remove candidate. playwright standalone alongside @playwright/test is likely redundant. Whop embedded components are current; do not touch. Majors available but not wanted now: lucide-react 1.x (184 importing files), framer-motion 13, jsdom 30, eslint 10, TypeScript 7.

Counts

  • Meaningful updates worth doing now (A): ~9 backend + ~12 frontend (nearly all patch/minor, most lockfile-only).
  • Major/high-risk upgrades needing their own tickets (B): backend 2 (@whop/sdk, pg pair); frontend 4 (lucide 1.x, framer-motion 13, jsdom 30 pair, eslint 10).
  • Deliberately untouched: Prisma family, Whop invoice alias, Express, TypeScript 5, @types/node majors, dotenv 17, AWS SDK drift.
  • Suspicious/unused: backend @noble/ciphers, date-fns, @types/ws; frontend @dnd-kit/*, standalone playwright.
  • Security: 4 backend advisories + 1 frontend advisory fixed by in-range refreshes (see Security findings). Remainder is transitive/dev-only or needs a parent minor bump (discord.js → ws/undici).

Phase 1 — Environment (both repos) ​

AspectBackendFrontend
Node expectationNo engines, no .nvmrc; CI setup-node: 22, Docker node:22-bookworm-slim → Node 22 is the contractSame: CI Node 22, Docker node:22-bookworm-slim, no engines
Package manager / lockfilenpm, package-lock.json, lockfileVersion: 3, Docker/CI use frozen npm ciSame
TypeScript^5.9.3, installed 5.9.3 = latest 5.x; target es2020, module commonjs, strict, skipLibCheck^5 (major range), installed 5.9.3; strict, bundler resolution, react-jsx
Framework/runtimeExpress ^5.2.1 (installed 5.2.1 = latest), Prisma 7.10.0, pg 8Next 16.3.3 exact, React ^19.2.1, Tailwind ^4
Build/test commandsbuild: tsc, test: offline suite via scripts/runTests.cjs; --integration, --authority, --campaign-funding suites gated behind DB env; start: node dist/index.jsbuild: next build, lint: eslint, test: node --import tsx --test tests/**; test:charts, campaign E2E scripts/e2e/run-campaigns.mjs; CI also installs Playwright Chromium
Versioning styleMixed: exact pins for Prisma family (7.10.0), @whop/sdk (1.1.2), pg (8.16.3), @types/pg (8.16.0); caret everywhere elseMixed: exact for next/eslint-config-next (16.3.3) and playwright (1.63.0); caret for most; major-only ranges for tailwindcss/@tailwindcss/postcss (^4), typescript (^5), eslint (^9), @types/react* (^19), @types/node (^20)
Runtime constraint on upgradesAnything requiring Node >22 is out (nothing proposed does). ts-node only drives dev/scripts; production runs compiled dist/ (+ prisma generate postinstall needs dummy DATABASE_URL at install)output: standalone Docker image; NEXT_PUBLIC_* inlined at build time; nothing proposed changes that

No repo configuration constrains upgrade ranges beyond the exact pins above (all intentional — see per-package notes). Reproducibility comes from the frozen lockfile, so the broad ^4/^5/^9/^19/^20 frontend ranges are not a reproducibility problem and need no narrowing (see Types/toolchain note).


Backend ​

Legend — Recommendation: A update now · B separate ticket · C leave as-is · D investigate/possibly remove. Risk: Low/Med/High (migration + blast radius).

PackageCurrent (declared / installed)Latest StableRecommendationRiskReason
@aws-sdk/client-s3^3.1041.0 / 3.1041.03.1136.0CLowRapid release churn (~95 builds); S3 usage is basic Put/Get/Delete + presign (src/utils/storage/r2.ts). No security/correctness driver.
@aws-sdk/s3-request-presigner^3.1041.0 / 3.1041.03.1136.0CLowMust stay aligned with client-s3; same churn reasoning. If ever bumped, bump both together.
@noble/ciphers^2.1.1 / 2.1.12.4.0DLowZero imports in src/scripts (verified). Encryption uses node:crypto (src/utils/encryption.ts, AES-256-GCM). Candidate for removal after confirming no dynamic use.
@prisma/adapter-pg7.10.0 exact7.10.0CHigh if touchedLatest stable (latest tag for @prisma/client = 7.10.0). Pinned trio must move together; no material benefit in any newer release (only RCs exist).
@prisma/client7.10.0 exact7.10.0CHigh if touchedSame. Generator (prisma-client, CJS, extensionless imports) is load-bearing for compiled dist/; startup behavior recently stabilized — do not churn.
@types/qrcode^1.5.61.5.6CLowCurrent. Note: lives in dependencies though types-only; harmless, not worth churn (see §Unused).
@types/speakeasy^2.0.102.0.10CLowCurrent. Same miscategorization note as above.
@whop/sdk1.1.2 exact1.1.5BHighPatch-level behind but financial integration: auth, payouts/transfers, team listing, webhooks all flow through it. Own ticket with sandbox+live verification; never bundled.
@whop/sdk-invoices (npm:@whop/sdk@1.0.14)alias exact— (deliberate)CHigh if touchedDeliberate pin: src/utils/campaignFunding/whopProvider.ts documents the company_id invoice-creation contract pinned to 1.0.14 + WHOP_API_VERSION_DATE 2026-08-21-1. Consolidation is a separate investigation, not this audit.
axios^1.16.0 / 1.16.01.20.0ALowSecurity: GHSA prototype-pollution pair affects ≤1.17.0. In caret range → lockfile refresh only. Also moves form-data to fixed ^4.0.6 range (axios 1.20 dep). Used by Tax1099 client. Verify: build + offline tests.
cookie-parser^1.4.71.4.7CLowLatest.
cors^2.8.5 / 2.8.52.8.6ALowOne patch behind, in range. Refresh with Batch 1.
date-fns^4.1.0 / 4.1.04.4.0DLowZero imports in src/scripts (verified). Candidate for removal.
discord.js^14.26.4 / 14.26.414.27.0AMedOne minor behind. Bonus: only path to fixed transitive undici/ws (via @discordjs/ws → ws@8.19.0, both flagged). Used: src/api/server.ts bot client. Verify: build + offline tests + bot login/startup. If ws stays vulnerable after bump, add a ws override (separate decision).
dotenv^17.2.3 / 17.4.218.0.1CLowInstalled 17.4.2 = latest 17.x. v18 is a new major; usage is only side-effect import 'dotenv/config' — zero benefit to major churn now.
express^5.2.15.2.1CMed if touchedLatest. Express 5 migration already done (router@2.2.0, path-to-regexp@8 chain healthy). No concerns left.
express-rate-limit^8.5.0 / 8.5.08.7.0ALowTwo minors, in range. Pairs with ip-address fix (its dep range ^10.2.0 allows the fixed 10.7.2). Verify rate-limit behavior via existing e2e rate-limit test.
helmet^8.1.0 / 8.1.08.3.0ALowTwo minors, in range. Header-only behavior; verify no CSP/header snapshot tests break.
iso8601-duration^2.1.3 / 2.1.32.1.4ALowOne patch, in range. Used by src/utils/youtube.ts.
jsonwebtoken^9.0.39.0.3CHigh if touchedLatest; auth-critical, no reason to move.
pdf-lib^1.17.11.17.1CLowLatest. Used by tax PDF generator.
pg8.16.3 exact8.23.0BMedSeven minors behind, but exact pin + known DB-timeout sensitivity + adapter coupling → own ticket with startup/pool-behavior verification (see Batch 2 note). Must move with @types/pg.
qrcode^1.5.41.5.4CLowLatest. Used by TOTP route.
resend^6.8.0 / 6.8.06.28.1AMed20 minors but in range; concrete payoff: 6.28.x deps drop svix entirely (now postal-mime + standardwebhooks), eliminating the flagged svix→uuid advisory chain. Email is non-critical path; verify with campaign-funding suite (it mocks/uses resend paths). Batch 2 (tested with discord bump).
speakeasy^2.0.02.0.0CMed if touchedLatest published, but upstream is effectively unmaintained — that is a watch item, not an action: TOTP auth depends on it, replacement would be a migration project. Do not churn now.
zod^4.3.5 / 4.3.54.6.5ALowThree minors, additive in Zod 4; 49 importing files but no breaking-change signal. In range. Verify with offline + campaign-funding suites (validation-heavy).
@types/cookie-parser^1.4.101.4.10CLowCurrent.
@types/cors^2.8.192.8.19CLowCurrent.
@types/express^5.0.65.0.6CLowCurrent; v5 types correct for Express 5.
@types/jsonwebtoken^9.0.109.0.10CLowCurrent.
@types/node^24.10.1 / 24.10.126.6.2 (major) / 24.13.x (line)A (within 24.x)LowOverall "major behind" is intentional (Node 22 runtime; v26 types unnecessary). Within-line 24.10.1 → 24.13.x is in caret range — refresh with Batch 1. Do NOT jump to v26.
@types/pg8.16.0 exact8.23.1BMedPaired with pg; move together in the pg ticket.
@types/ws^8.18.18.18.1DLowNo ws imports anywhere in src/scripts; ws itself is only transitive (via @discordjs/ws). Likely leftover. Removal candidate pending tsc proof.
prisma (dev)7.10.0 exact8.0.0-rc.15 (latest tag; prev: 7.10.0)CHigh if touchedOn latest stable line. v8 is prerelease — never chase latest here. Pinned with the client/adapter trio.
ts-node^10.9.210.9.2CLowLatest 10.x. Still the right tool: dev entry (dev, deploy, scrape scripts, rbac:*) all invoke ts-node; production runs compiled dist/. No tangible benefit to a tsx/swc migration — explicitly not proposed.
typescript^5.9.37.0.2 (latest; Go rewrite) / 5.9.3 (5.x line)CHigh if touched5.9.3 = latest 5.x. v7 is a new toolchain generation — defer well past MVP.

Backend detailed notes (only where useful) ​

  • Prisma: npm view confirms @prisma/client latest = 7.10.0 (we are current) while the prisma CLI's latest tag already points at 8.0.0-rc.15 (prev: 7.10.0). This is exactly the trap the task warns about: a naive "upgrade to latest" would install a release candidate of the migration CLI against stable client/adapter. Stay on 7.10.0 across all three; revisit only when Prisma 8 goes stable and offers something we need (nothing on the horizon affects our usage: Postgres adapter + CJS generator + standard migrations).
  • Whop alias: whopProvider.ts (invoice path: funding, fee policy charge_buyer_fee mapping, reconciliation) imports WhopClient from @whop/sdk-invoices (= real SDK 1.0.14), while everything else (whopClient.ts, transfers, team listing) uses @whop/sdk@1.1.2. The header comment pins the company_id invoice contract to 1.0.14 + API version date 2026-08-21-1. So the alias is load-bearing, not accidental: it lets invoice calls stay on the verified contract while the general client moves. Divergence cost (two SDK copies) is real but small and understood; consolidation = behavior re-verification against live/sandbox money paths → separate ticket at best, likely never.
  • pg exact pin: src/utils/prismaClient.ts builds every client through PrismaPg (node-postgres pool with explicit timeouts — the file carries scar tissue about Neon/ETIMEDOUT). pg is never imported directly, but it is a runtime peer of the adapter, so the direct dep is correct. The exact pin is presumably caution around that history; lifting to ^8 + 8.23.0 is reasonable but belongs in its own PR with API-startup measurement (measure:api-startup) + integration runs.
  • @types/qrcode / @types/speakeasy in dependencies: used (TOTP route + middleware import both), just miscategorized — types-only packages conventionally live in devDependencies. Moving them is cosmetically correct but touches the install graph for zero runtime effect; leave until a real edit touches those lines.
  • Overrides: all five still resolve to real parents (see §Overrides). None can be removed now — notably qs and ip-address ranges already permit the fixed versions; only the lockfile is stale.

Frontend ​

PackageCurrent (declared / installed)Latest StableRecommendationRiskReason
next16.3.3 exact16.3.5AMedOne patch behind latest stable (latest: 16.3.5; canary is 16.4.0-canary, avoid). Conservative framework judgment still favors taking a same-major patch (likely CVE/bug fixes + the transitive fixes npm audit wants). Verify: build + lint + tests + Playwright campaign E2E.
eslint-config-next16.3.3 exact16.3.5ALowMust stay exactly synchronized with next (it lints against Next internals; our eslint.config.mjs extends its core-web-vitals + typescript presets). Move lockstep with next.
react^19.2.1 / 19.2.119.3.0AMedOne minor, in range. Keep paired with react-dom + both @types/*. No canary/experimental.
react-dom^19.2.1 / 19.2.119.3.0AMedPaired with react (same PR, same verification).
@types/react^19 / 19.2.719.3.0ALowIn range; move with React pair.
@types/react-dom^19 / 19.2.319.3.0ALowIn range; move with React pair.
@dnd-kit/core^6.3.1 / 6.3.16.3.1DLowCurrent version but zero imports repo-wide (only package.json mentions; "sortable" hits are an unrelated local component name + HTML draggable). All three are dead weight.
@dnd-kit/sortable^10.0.0 / 10.0.010.0.0DLowSame. (Compat note becomes moot if removed: sortable@10 peers on core@^6.3.0, currently consistent.)
@dnd-kit/utilities^3.2.2 / 3.2.23.2.2DLowSame. Verify removal with build + lint + tests, then delete all three in one PR.
@tanstack/react-query^5.103.0 / 5.103.05.103.2ALowTwo patches, in range. Used by marketing hooks/providers.
@vercel/analytics^2.0.12.0.1CLowLatest. (Telemetry wrapper redacts private report URLs — untouched.)
@vercel/speed-insights^2.0.02.0.0CLowLatest.
@whop/embedded-components-react-js^1.2.01.2.0CHigh if touchedLatest; high-risk embed surface (support screen). Do not touch.
@whop/embedded-components-vanilla-js^1.2.01.2.0CHigh if touchedLatest; paired with the React wrapper — keep synchronized, currently are.
clsx^2.1.12.1.1CLowLatest (latest tag = 2.1.1). Paired with tailwind-merge in shared/lib/utils.ts.
framer-motion^12.23.24 / 12.23.2413.4.0BMedMajor behind (v13 latest). Used across marketing surfaces. No security driver; motion-behavior regression risk across many components → own ticket, post-MVP.
lenis^1.3.261.3.26CLowLatest. Used by SmoothScroll.
lucide-react^0.555.0 / 0.555.01.47.0BMedMajor line behind (1.x stable after 0.555.0; caret on 0.x correctly holds us back). 184 importing files — icon renames/removals are the risk. Own ticket with visual review; post-MVP.
react-hot-toast^2.6.0 / 2.6.02.6.1ALowOne patch, in range. Toast system has dedicated tests (tests/toast.test.tsx).
tailwind-merge^3.4.0 / 3.4.03.7.0ALowThree minors, in range; class-conflict resolution only. Covered by build + tests.
@playwright/test^1.63.0 / 1.63.01.63.0CLowCurrent. Coordinated pair with playwright below — versions match, good.
playwright1.63.0 exact1.63.0C (version) / D (presence)LowVersion current, but the standalone package is likely redundant: @playwright/test already ships the playwright CLI used by CI (npx playwright install --with-deps chromium). Investigate: remove playwright, run npm ci + install + E2E in CI; keep if the bin disappears.
@tailwindcss/postcss^4 / 4.1.174.3.3AMedTwo minors behind the Tailwind line, in range. Paired with tailwindcss — always bump together (plugin version tracks core). CSS-output diff risk → verify build + visual/E2E.
@testing-library/react^16.3.2 / 16.3.316.3.3CLowAlready resolving to latest via caret. Correct for React 19.
@testing-library/user-event^14.6.114.6.7CLowIn range; lockfile will resolve latest on refresh.
@types/jsdom^21.1.730.0.0BLow-MedMajor behind, but paired with jsdom major (see below). Move only together with jsdom@30 in the test-infra ticket.
@types/node^20 / 20.19.2526.6.2CLow"Major behind" is fine and intentional enough: runtime is Node 22, lockfile pins 20.19.25 reproducibly, no missing-API pain reported. No reason to pin narrower (frozen lockfile already guarantees reproducibility) and no reason to jump majors. Leave.
eslint^9 / 9.39.110.11.0C (stay on 9) / B (v10 later)Med if touched^9 correctly holds below v10 (whose engines require Node `^20.19
eslint-config-next(see next row)—A—Paired move with next.
jsdom^26.1.0 / 26.1.030.1.0BLow-MedTwo majors behind, but test-only and working (5+ test files construct JSDOM directly; engines on v30 wants Node ≥22 — fine). No capability need → test-infra ticket with @types/jsdom@30, post-MVP.
tailwindcss^4 / 4.1.174.3.3AMedSame as plugin: paired minor bump, verify build + E2E (generated CSS changes).
tsx^4.21.0 / 4.23.134.23.15ALowTwo patches, in range. Load-bearing for npm test (node --import tsx).
typescript^5 / 5.9.37.0.2CHigh if touched5.9.3 = latest 5.x; ^5 correctly excludes the v7 rewrite. Never chase.
postcss (override)^8.5.10 / 8.5.148.5.28A (refresh)LowOverride range already allows the fixed 8.5.28; installed 8.5.14 is flagged HIGH (see Security). Lockfile refresh only; keep the override (see §Overrides).

Frontend detailed notes ​

  • Next 16.3.3 → 16.3.5: latest = 16.3.5, so this is a same-major patch, not a framework migration. The repo already lives on the v16 line (agent-rules block, turbopack root, output: standalone). Take it, with eslint-config-next lockstep (exact–exact pairing preserved). Do not look at 16.4.0-canary.
  • React 19.2 → 19.3: minor, react/react-dom/@types/* move as one unit. @tanstack/react-query@5 peers on ^18 || ^19 — unaffected.
  • Tailwind v4 minors (4.1.17 → 4.3.3): core + @tailwindcss/postcss move together; the postcss override (^8.5.10) stays and continues to dedupe the single postcss@8 copy shared with Next. Verify with a production build (CSS diff is the risk, not types).
  • Broad major ranges (^4, ^5, ^9, ^19, ^20): assessed, no narrowing recommended. Reproducibility is enforced by the frozen lockfile (npm ci in CI/Docker); narrowing would only add edit churn while reducing automatic uptake of compatible fixes. The two that matter (next, eslint-config-next) are already exact.
  • @dnd-kit/*: the only "sortable" references in code are a local AdminPvTrackerSortableHead component (custom sort headers, no library) and an HTML draggable attribute. No DndContext/SortableContext/drag sensors anywhere. Safe removal candidate — one PR deleting all three deps after build+lint+test proof.
  • Whop embeds: both at latest (1.2.0), versions synchronized, used by the support screen. High-risk surface, zero update available anyway — untouched by definition.

Overrides ​

Backend ​

OverrideChain (via npm ls)Original reason (inferred)Still required?
follow-redirects@^1.16.0axios@1.16.0 → follow-redirects@1.16.0Pin the redirect handler to its fixed release (axios CVE history lives here).Yes. Installed = latest (1.16.0); axios 1.20 still deps on ^1.16.0. Keep.
ip-address@^10.2.0express-rate-limit@8.5.0 → ip-address@10.2.0Force a newer ip-address than the limiter's floor (8.5.0's own dep was 10.1.0).Yes — and refresh. Range already allows the fixed 10.7.2; lockfile still holds vulnerable 10.2.0. npm update ip-address (no package.json change). Never remove: the limiter's floor is still old.
lodash@^4.18.1discord.js → @discordjs/builders → @sapphire/shapeshift → lodash; also prisma → @prisma/studio-core → @visx/* → lodashDedupe/force lodash past historic vulns across two unrelated subtrees.Yes. Installed = latest (4.18.1), dedupes both chains. Harmless to keep.
path-to-regexp@^8.4.2express@5.2.1 → router@2.2.0 → path-to-regexp@8.4.2Enforce v8 (Express 5's router line; v8 fixed the ReDoS-class issues of the v6/v7 line).Yes. Installed = latest. Removing risks a nested v6/v7 reappearing under some future router bump.
qs@^6.15.1express@5.2.1 → qs and → body-parser → qsForce qs past its DoS advisories (express's own floor is only ^6.14.0).Yes — and refresh. Range allows fixed 6.16.0; lockfile holds flagged 6.15.1. Same lockfile-only refresh as ip-address.

Frontend ​

OverrideChainOriginal reason (inferred)Still required?
postcss@^8.5.10@tailwindcss/postcss@4.1.17 → postcss@8.5.14 and next@16.3.3 → postcss@8.5.14 (deduped single copy)Force a single, modern PostCSS 8 under both Tailwind v4 and Next (Tailwind v4 had peer churn around PostCSS versions).Yes — and refresh. Range allows fixed 8.5.28; lockfile holds flagged 8.5.14. Keep the override permanently (it guarantees the dedupe); just refresh the lockfile.

Net: no override can be removed. Three (ip-address, qs, postcss) additionally need a lockfile refresh because their ranges already cover the security-fixed versions.


Potentially unused/redundant dependencies ​

All verified by import grep (word-boundary, src/scripts/tests/surfaces/shared, generated Prisma client excluded). "Unused" below means zero static and no config/CLI/dynamic reference found; removal still requires the stated proof.

Backend

  1. @noble/ciphers (D) — no noble reference anywhere in src/scripts. AES-GCM needs are served by node:crypto (src/utils/encryption.ts, TIN helper in src/utils/tax/tin.ts). Likely added speculatively. Proof needed before removal: npm why @noble/ciphers, full test suite + tsc after removal, confirm no dynamic require('…ciphers…').
  2. date-fns (D) — no date-fns import anywhere. Date handling is native Date + iso8601-duration (YouTube durations). Proof: same as above.
  3. @types/ws (D) — no ws import anywhere; ws exists only transitively (discord.js → @discordjs/ws → ws@8.19.0). @types/ws therefore types nothing we import. Proof: remove + tsc clean.
  4. @types/qrcode / @types/speakeasy placement (note, not removal) — both genuinely used (totp.ts, totpAuth.ts), but declared under dependencies instead of devDependencies. Cosmetically wrong, functionally harmless. Do not churn the install graph to fix; correct only if those lines are edited for another reason.
  5. pg is correctly placed — never imported directly, but it is the runtime peer behind PrismaPg (src/utils/prismaClient.ts). Not unused. Keep with @types/pg.

Frontend

  1. @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities (D) — zero imports repo-wide (verified across .ts/.tsx/.mjs, excluding node_modules/.next/package-lock). The only "sortable" hits are a hand-rolled AdminPvTrackerSortableHead and an HTML attribute. Remove all three in one PR after next build + eslint + npm test proof.
  2. playwright standalone (D) — version-fine (1.63.0, matches @playwright/test), but redundant: CI's npx playwright install --with-deps chromium bin is also provided by @playwright/test. Proof: drop it, npm ci, re-run the Chromium install + campaign E2E in CI; restore if the bin is missing.
  3. Correctly-kept pairs: clsx + tailwind-merge (both used in shared/lib/utils.ts); @vercel/analytics + @vercel/speed-insights (both rendered in Telemetry.tsx); jsdom + @types/jsdom (5+ test files import JSDOM directly; tsx powers npm test); both Whop embed packages (support screen imports).

Security findings ​

Only actionable items. (npm audit raw totals: backend 18, frontend 12 — mostly transitive/dev-only noise, not reproduced here.)

Backend — fix now via in-range refresh (Batch 1) ​

FindingExposureFix
axios@1.16.0 HIGH — prototype-pollution pair (≤1.17.0)Runtime: Tax1099 HTTP client. Moderate severity advisories, network-reachable parsing.Refresh to 1.20.0 (in ^1.16.0 range). Simultaneously moves form-data into fixed ^4.0.6 range (kills the HIGH form-data CRLF advisory, same chain).
qs@6.15.1 MODERATE — DoS pair (≤6.15.3)Runtime: every Express query parse. Override ^6.15.1 already allows 6.16.0.Lockfile refresh to 6.16.0.
ip-address@10.2.0 HIGH — SSRF/trust-boundary bypass pair (≤10.3.0)Runtime: express-rate-limit IP handling (trust-boundary relevant). Override ^10.2.0 already allows 10.7.2.Lockfile refresh to 10.7.2.
resend@6.8.0 → svix@1.84.1 → uuid@10.0.0 MODERATEBuild/runtime email path (non-critical). resend@6.28.1 drops svix entirely.Bump within ^6.8.0 (Batch 2 with verification).

Backend — needs a parent bump (Batch 2) ​

FindingExposureFix
ws@8.19.0 HIGH + undici HIGH (via discord.js → @discordjs/ws)Bot gateway connection (long-lived WS). Not API-request path, but persistent.discord.js@14.27.0 minor bump; re-run npm ls ws undici. If ws remains in flagged range, add a ws override as a separate deliberate decision (do not sneak it into the bump PR).
body-parser@2.2.2 LOW (limit-value DoS)Transitive via Express; only triggers on explicitly misconfigured limits.No action: fixed upstream only in a future Express/body-parser release. Watch item.

Backend — explicitly not actionable ​

  • prisma → mysql2 / deepmerge-ts HIGHs: dev-only (prisma CLI + Studio), never in the production image path (dist/ + generated client). Fix offered is prisma@6.19.3 — a downgrade-major the auditor suggests blindly; ignore. Resolves when Prisma 8 goes stable and we adopt it deliberately.
  • @discordjs/rest → undici MODERATE: same discord subtree as above; covered by the discord bump.

Frontend — fix now (Batches 1/3) ​

FindingExposureFix
postcss@8.5.14 HIGH (range ≤8.5.22)Build-time (CSS processing in next build + Tailwind plugin). Not runtime user input, but trivially fixable.Lockfile refresh to 8.5.28 (in override range). Verify next build.

Frontend — covered by proposed bumps, no separate action ​

  • nanoid, flatted, minimatch, picomatch, brace-expansion, browserslist, js-yaml, ajv, baseline-browser-mapping, @babel/core, @humanfs/node: all transitive under eslint/next/tailwind subtrees; fixAvailable: true via the next@16.3.5 + Tailwind 4.3.3 bumps. Re-run npm audit after Batch 3 and confirm attrition rather than chasing each leaf.

All commands are illustrative — do not run the mutating ones until a ticket explicitly authorizes them. Read-only verification (npm ls, npm audit, npm view) may run anytime.

Batch 1 — trivial/low-risk maintenance (lockfile refreshes, minimal or no package.json edits) ​

Scope (backend): axios→1.20.0, cors→2.8.6, express-rate-limit→8.7.0 + ip-address→10.7.2, helmet→8.3.0, iso8601-duration→2.1.4, zod→4.3.5→4.6.5, @types/node→24.13.x, qs→6.16.0, form-data (via axios). Frontend: postcss→8.5.28, tsx→4.23.15 (+ @testing-library/user-event resolving to 14.6.7 if not already). Method: npm update <name> per package (respects existing ranges; not npm install <name>@latest, which would breach exact pins and jump majors).

Backend verification: npm run build · npm test (offline) · npm run test:authority if auth-adjacent files touched (they aren't, but cheap) · API startup smoke (measure:api-startup or boot + /api/health) · npm ls qs ip-address follow-redirects confirms single deduped copies · npm audit confirms the four advisories cleared. Frontend verification: npm run build · npm run lint · npm test · npm run test:charts.

Batch 2 — backend ecosystem (one PR, behavior-adjacent minors) ​

Scope: discord.js@14.27.0, resend@6.28.1. Why together: both are routine minors with small but real behavior surfaces (gateway connection; email provider SDK), and both close audit chains (ws/undici via discord; svix/uuid via resend). Kept separate from Batch 1 so a behavior regression is attributable. Verification: everything in Batch 1 backend plus npm run test:integration (DB) · campaign-funding suite (test:campaign-funding) for the resend paths · bot login/startup check · npm ls ws undici svix to confirm chain movement · Prisma generate untouched (no schema change expected).

Batch 3 — frontend ecosystem (one PR, UI/tooling minors + patch framework) ​

Scope: next 16.3.3→16.3.5 + eslint-config-next 16.3.3→16.3.5 (lockstep exacts) · react + react-dom + @types/react + @types/react-dom → 19.3.0 line · tailwindcss + @tailwindcss/postcss → 4.3.3 line · tailwind-merge→3.7.0, @tanstack/react-query→5.103.2, react-hot-toast→2.6.1. Why together: coupled framework/CSS/rendering behavior; a visual or hydration regression must be attributable to this PR alone — hence no Whop/dnd-kit/lucide changes inside it. Verification: npm run build · npm run lint · npm test · test:charts · campaign E2E (test:e2e:campaigns, Playwright/Chromium) · npm audit to confirm transitive attrition.

Batch 4 — framework/toolchain ​

Nothing justified. Intentionally empty. TypeScript stays on 5.9.3 (v7 is a rewrite generation), ESLint stays on 9 (v10 is a new major), ts-node stays (no tangible benefit to migrating the script runtime). Revisit post-MVP.

Batch 5 — high-risk integrations (tickets only, no action in this audit) ​

  1. Whop general SDK 1.1.2 → 1.1.5 — own ticket: sandbox invoice/payout/transfer dry-runs, webhook signature verification, auth + funding + campaign-funding + authority suites, then staged live verification. Never bundled with maintenance.
  2. Whop invoice-alias consolidation (1.0.14 → unified) — investigation ticket first (does the company_id contract still require the old client?), implementation only with finance-owner sign-off.
  3. pg 8.16.3 + @types/pg 8.16.0 → 8.23.x — own small ticket: startup measurement, pool/timeout behavior review (prismaClient.ts notes), integration suite. Could ride alongside Batch 2's verification but ships as its own PR for revertability.
  4. Prisma 8 (when stable) — adopt only on a stable 8.x with a documented need; full migration replay per repo safety rules.

Deferred upgrades ​

UpgradeWhy it waits
Prisma 8 (8.0.0-rc.x)Prerelease. Current 7.10.0 is the stable line for all three packages; zero material benefit; generator/startup behavior recently stabilized.
TypeScript 7 (+ frontend ^5 staying)New toolchain generation (Go rewrite). Backend 5.9.3 is latest 5.x; no language feature need. Post-MVP at earliest.
dotenv 17 → 18New major; usage is side-effect-only config loading. No benefit, nonzero behavior risk.
AWS SDK 3.1041 → 3.1136Pure churn (~95 releases); S3 usage is elementary and working. Refresh only if a CVE touches the exact APIs used.
lucide-react 0.555 → 1.xMajor with 184 importing files; icon rename/removal risk needs visual review. Follow-up ticket (B), post-MVP.
framer-motion 12 → 13New major (v13); animation behavior risk across marketing surfaces. Follow-up ticket (B), post-MVP.
jsdom 26 → 30 (+ @types/jsdom 21 → 30)Two-major jump in test infra; current setup works on Node 22. Paired ticket (B), post-MVP.
eslint 9 → 10New major with config/rule churn; v9 current and supported by eslint-config-next@16. Ticket (B), post-MVP.
@types/node 20 → 22/24/26 (frontend), 24 → 26 (backend)No missing-API pain; frozen lockfile already reproducible. Jumping types majors buys nothing pre-MVP.
speakeasy replacementUpstream stagnant but functional and pinned at its only release line; replacing TOTP is a migration project, not maintenance. Watch only.
body-parser LOW advisoryFix exists only in a future Express-line release; not exploitable under our configuration. Watch npm audit after each Express bump.
Prisma dev-only advisories (mysql2, deepmerge-ts)Never shipped to production; auditor-suggested "fix" is a downgrade-major. Ignore until Prisma 8 adoption.
@dnd-kit/* version questionsMoot — packages are unused; the decision is remove vs keep, not which version.
ts-node → tsx migrationNo tangible benefit: scripts run fine, production uses compiled output. Explicitly not proposed.

Final recommendation ​

1. Do now (Batch 1 — lockfile-only refreshes, one PR per repo): Backend: axios, cors, express-rate-limit + ip-address, helmet, iso8601-duration, zod, @types/node, qs — clears 3 real advisories plus hardening. Frontend: postcss, tsx — clears the HIGH build-time advisory. Verification per Batch 1.

2. Open follow-up tickets for (in priority order): a. Batch 2 PR — discord.js@14.27 + resend@6.28 (closes remaining runtime advisory chains; needs bot + email verification). b. Batch 3 PR — next@16.3.5 + eslint-config-next lockstep, React 19.3 quartet, Tailwind 4.3.3 pair, tailwind-merge, react-query, hot-toast (needs build + lint + unit + chart + Playwright E2E). c. Removal PR — @dnd-kit/* ×3 (frontend) after proof; separately @noble/ciphers + date-fns + @types/ws (backend) after npm why + tsc + suite proof. Plus a verdict on standalone playwright redundancy. d. pg + @types/pg → 8.23.x small ticket with startup/pool verification. e. Whop general-SDK 1.1.2 → 1.1.5 ticket (sandbox → staged-live verification; finance-owner awareness). Invoice-alias consolidation stays an investigation, defaulting to "leave." f. Post-MVP backlog: lucide 1.x, framer-motion 13, jsdom 30 pair, eslint 10, Prisma 8 (stable only), TS 7 (far future).

3. Deliberately leave alone: Prisma trio (7.10.0), @whop/sdk-invoices alias (1.0.14 + API date), Express 5 stack, jsonwebtoken, pdf-lib/qrcode/speakeasy, cookie-parser, dotenv 17, AWS SDK pair alignment, ts-node, TypeScript 5, all five backend overrides + the postcss override, Whop embedded components, @vercel/*, clsx, lenis, @playwright/test version, @testing-library/* versions, @types/node majors, and every Deferred item above. The boring strategy is the correct one: lockfile refreshes for security, paired minors for hygiene, tickets for everything with a blast radius.