πŸ“¦ Dependencies & Licensing

πŸ“‹ Summary

The application depends on a small set of 15 direct runtime libraries, which is a healthy, low-sprawl position. However, the dependency audit reports 24 known vulnerabilities (3 critical, 13 high), 11 of which reach production code. The single most important item is the web framework itself: Next.js is pinned to exactly 16.2.0, a release affected by roughly 26 published advisories, including critical remote-code-execution issues in a feature the product actually uses (generated tab icons). A second production concern is the spreadsheet library xlsx, which has not been updated on npm since 2022, has unfixed vulnerabilities, and is used to parse uploaded files on the server. Two declared libraries are not used at all. On licensing the picture is clean for a commercial acquirer: everything shipped is permissive, with only weak-copyleft (LGPL, MPL) or dual-licensed components that are used unmodified, and the product's own code is proprietary to a single named individual β€” which makes clear IP assignment a contractual must.

🎯 Rating

πŸ”΄ ●●○○○ 2 / 5 β€” Red. A small, sensible dependency set is undermined by a critically vulnerable, exact-pinned framework and an abandoned parser handling untrusted uploads, with no automated dependency scanning to catch either.

πŸ” Findings

Part A β€” Dependencies

A1. Direct runtime dependencies

PackageIn useLatestPurposeWhere usedFlags
next16.2.0 (exact)16.4.0Framework, routing, RSC, image/OG generationWhole appCritical advisories; exact pin
react / react-dom19.2.4 (exact)19.3.0UIWhole appβ€”
@supabase/supabase-js2.99.32.117.2DB, storage, auth client18 files import directly; 154 files use a client wrapperBehind
@supabase/ssr0.9.00.12.7Cookie-based auth in RSC/route handlers3 files (src/lib/supabase/*)Pre-1.0
resend6.20.06.32.1Transactional e-mail4 filesβ€”
mammoth1.12.01.13.0Read copywriters' .docx decks (browser)src/app/(app)/campaign/[id]/ads/import-copy-modal.tsxTransitive moderate vulns (argparse/sprintf-js)
xlsx (SheetJS)0.18.50.18.5 (npm, 2022-03-24)Parse uploaded spreadsheets (product sheets, schedules)src/lib/product-sheet-file.ts, called server-side from src/app/api/campaigns/[id]/products/route.ts:60 and client-side from plan/schedule-import.tsxUnmaintained on npm; high-severity prototype pollution + ReDoS, no fix
ag-psd31.0.231.0.2Flatten .psd to PNG in the browser1 fileβ€”
fflate0.8.20.8.3Build handover zipsrc/lib/handover-zip.tsModerate advisory (ZIP64 infinite loop on unzip; app only zips)
lucide-react0.577.01.52.0Icons55 filesA major behind
clsx, tailwind-merge2.1.1, 3.5.02.1.1, 3.7.0Class-name utilities1 file eachβ€”
date-fns4.1.04.4.0β€”Not imported anywhereUnused
google-auth-library10.6.211.1.0β€”Not imported anywhereUnused

[Observed] package.json, npm outdated, grep -rlE "from '<pkg>'" src.

Unmaintained (no release in 2+ years): xlsx only (npm release 0.18.5 dated 2022-03-24; the vendor now distributes newer builds from its own CDN rather than npm). [Observed] No deprecated direct dependency is reported by npm; node-domexception (transitive) is deprecated. [Observed] npm ci warnings.

A2. Vulnerability audit (npm audit, 2026-10-07)

ScopeπŸ”΄ Critical🟠 HighModerateβšͺ LowTotal
All (incl. dev)3137124
Production only (--omit=dev)155011

Key items:

PackageSeverityScopeIssue (advisory titles, summarised)Fix
next 16.2.0πŸ”΄ CriticalProd~26 advisories: RCE in next/og ImageResponse (<16.3.6) β€” used by src/app/icon.tsx and src/app/apple-icon.tsx; RCE in Image Optimisation with AVIF (<16.3.3); several middleware/proxy bypass issues (<16.2.5 / <16.2.11); SSRF in rewrites and WebSocket upgrades; multiple DoS and cache-poisoning issuesUpgrade to β‰₯ 16.4.0
postcss, sharp (via next)🟠 HighProdXSS in CSS stringify; libvips CVEsArrive with the Next upgrade
xlsx 0.18.5🟠 HighProdPrototype pollution; ReDoSNo npm fix β€” replace
@xmldom/xmldom (via mammoth)🟠 HighProdXML fragment injectionnpm audit fix
fflate, mammoth/argparse/sprintf-jsModerateProdDoS-class issuesPatch / minor bumps
vitest, tinypool, @vitest/mockerπŸ”΄ CriticalDev onlyRCE/path traversal in the test runnerVitest 5 (not shipped to users)
eslint-config-next tree (braces, micromatch, fast-glob)🟠 HighDev onlyReDoS/DoSBump with Next

[Observed] npm audit, npm audit --json, npm audit --omit=dev. Whether the production deployments are actually running 16.2.0 depends on the deployed lockfile. [Unavailable β€” requires Vercel deployment access to confirm the deployed build.]

A3. Vendored, forked or patched code

  • No patches/ directory, no patch-package, no forked git dependencies. [Observed]
  • src/types/mammoth.d.ts is a hand-written type declaration (not a fork). [Observed]
  • Studio code was moved to a separate private repository (FS002-dev/campaign-studio) on 2026-09-19; src/lib/artwork/ (fit arithmetic, renderer) stayed here. This is in-house code, not a vendored library, but its counterpart lives in another repository the buyer should also obtain. [Observed] CLAUDE.md "Parked decisions"; [Unavailable] the other repository.
  • Two Python audit utilities (audits/*.py) and Node scripts (scripts/) are development tooling with no declared dependency manifest (no requirements.txt). [Observed]

A4. Major dependency relationships

Part B β€” Licensing

B1. Direct dependency licences

All 15 direct runtime dependencies are permissive: MIT (11), Apache-2.0 (xlsx, google-auth-library), ISC (lucide-react), BSD-2-Clause (mammoth). [Observed] each package's package.json.

B2. Whole installed tree (license-checker --summary)

MIT 417 Β· Apache-2.0 41 Β· ISC 26 Β· BSD-2 11 Β· BSD-3 8 Β· BlueOak-1.0.0 6 Β· MPL-2.0 5 Β· LGPL-3.0-or-later 2 Β· MIT AND Zlib 2 Β· and singletons: Python-2.0, CC-BY-4.0, BSD*, Unlicense, (MIT OR GPL-3.0-or-later), CC0-1.0, MIT-0, 0BSD, UNLICENSED (the product itself).

Licence of notePackage(s)Shipped?Implication for a commercial acquirer
LGPL-3.0-or-later@img/sharp-libvips-* (via next β†’ sharp)Server runtime on Vercel, dynamically linked, unmodifiedLow risk. LGPL permits use from proprietary software; obligations (allow relinking, provide notice) are met by using the stock binary. Matters more if the product is ever distributed on-premise.
MPL-2.0lightningcss (build), axe-core, @axe-core/playwright (test)Build/test onlyFile-level copyleft only on modified MPL files; none are modified. Negligible.
(MIT OR GPL-3.0-or-later)jszip (via mammoth)Browser bundleDual-licensed; the acquirer elects MIT. No obligation.
CC-BY-4.0caniuse-liteBuild dataAttribution data; standard across the ecosystem. Negligible.
BSD* (unparsed)duck (transitive of mammoth)Browser bundleLicence string not SPDX-clean; confirm manually. Low.
GPL / AGPL / SSPL (strong copyleft)Noneβ€”β€”

B3. Product licence, notices and provenance

  • LICENSE: "Copyright (c) 2026 Matthew Prins, trading as Midshift. All rights reserved." β€” proprietary, owned by a named individual trading as Midshift, not a company. [Observed] LICENSE line 1. Any acquisition needs a written IP assignment from that individual (and from any other contributors whose work the squashed history hides). [Inferred]
  • package.json declares "license": "UNLICENSED" and "private": true, consistent with proprietary code. [Observed]
  • No NOTICE / third-party attribution file is produced for the shipped bundle. [Observed]
  • No licence policy or allow-list is enforced in CI. [Observed] .github/workflows/ci.yml
  • Code of uncertain provenance: the git history has been squashed to one commit by "Matthew Prins", so authorship of individual lines cannot be established from the repository. CLAUDE.md and code comments refer to work carried out across multiple "sessions", consistent with heavy AI-assisted development. [Inferred] Provenance of AI-generated code is not itself a licence breach, but the buyer should obtain warranties covering originality and third-party code. [Unavailable β€” requires original history and a contributor list.]
  • scripts/scrub.js enforces that no client-identifying material is tracked β€” a positive confidentiality control (passes: "nothing client-identifiable in 715 tracked files"). [Observed]

🧾 Evidence

  • npm ci (490 packages) β†’ npm audit, npm audit --json, npm audit --omit=dev β†’ "11 vulnerabilities (5 moderate, 5 high, 1 critical)".
  • node -e over audit.json listing every Next.js advisory title and affected range.
  • npm outdated; npm view xlsx 'time[0.18.5]' β†’ 2022-03-24.
  • license-checker --summary, license-checker --production --json.
  • npm ls jszip sharp β†’ mammoth@1.12.0 β†’ jszip@3.10.1, next@16.2.0 β†’ sharp@0.34.5.
  • grep -n "ImageResponse" src/app/icon.tsx src/app/apple-icon.tsx; src/app/api/campaigns/[id]/products/route.ts:54–60 (server-side sheetRows on an uploaded file).
  • Mermaid diagram validated (valid: true).

⚠️ Risks

RiskSeverityEffort
Next.js 16.2.0 with critical RCE and middleware-bypass advisories in production; exact pin prevents patch uptakeπŸ”΄ CriticalS
xlsx parses attacker-controllable uploads on the server with known, unfixable-on-npm prototype pollution / ReDoS🟠 HighS–M
No automated dependency/vulnerability scanning (no Dependabot/Renovate config, no npm audit in CI), so new advisories go unnoticed🟠 HighS
IP held by an individual; squashed history prevents verifying authorship🟠 High (transactional)S (legal)
Unused date-fns, google-auth-library widen supply-chain surfaceβšͺ LowS
Dev-only critical advisories (Vitest/tinypool) β€” affect developer and CI machines, not usersβšͺ LowS
No third-party NOTICE file for shipped bundleβšͺ LowS

βœ… Recommendations

RecommendationPriorityEffort
Upgrade next and eslint-config-next to β‰₯ 16.4.0 and redeploy every client deployment; verify the deployed versionP0 (before close)S
Replace xlsx (vendor CDN build β‰₯ 0.20.x or exceljs); at minimum, cap upload size and parse only in the browserP1S–M
Enable Dependabot or Renovate and add npm audit --omit=dev --audit-level=high to CIP1S
Run npm audit fix for the non-breaking transitive fixes; upgrade Vitest to 5P2S
Remove unused dependenciesP2S
Obtain a deed of IP assignment and originality warranties from the copyright holder; request unsquashed historyP0 (transactional)S
Add a licence allow-list check (e.g. license-checker --onlyAllow) and generate a NOTICE fileP3S