Fix upload path-traversal RCE vector, patch all known-vulnerable deps #1

Merged
joshua merged 2 commits from security/upload-path-traversal-and-dep-fixes into main 2026-08-28 12:44:22 +02:00
Owner

Summary

  • Fixes a path-traversal arbitrary-file-write vulnerability (CWE-22/CWE-73) in event-image, branding (logo/favicon), and event-attachment uploads — the stored filename embedded the unsanitized client-supplied original filename, allowing ../ sequences to escape the upload directory. Filenames are now always server-generated.
  • Patches all known-vulnerable dependencies across root/backend/frontend (npm audit now clean everywhere), including a critical unauthenticated Next.js RCE (GHSA-9qr9-h5gf-34mp) and moving express-rate-limit into backend/package.json (it was root-only, so a standalone cd backend && npm install never installed it).
  • Hardening: jwt.verify() now pins algorithms: ['HS256']; /uploads now serves with a restrictive CSP + X-Content-Type-Options: nosniff to neutralize SVG-embedded-script XSS.
  • Version bumped to 1.10.1, tagged v1.10.1.

Test plan

  • Backend Jest suite (21 tests) passes on the bumped dependencies
  • Backend boots and serves real HTTP requests on the bumped deps; confirmed CSP/nosniff headers present on real uploaded files
  • next build compiles and type-checks cleanly on the bumped frontend deps (verified against a live backend + real event data)
  • npm audit reports 0 vulnerabilities in root, backend, and frontend

https://claude.ai/code/session_01CSWFWQsjTc9GyffPiXEDQT

## Summary - Fixes a path-traversal arbitrary-file-write vulnerability (CWE-22/CWE-73) in event-image, branding (logo/favicon), and event-attachment uploads — the stored filename embedded the unsanitized client-supplied original filename, allowing `../` sequences to escape the upload directory. Filenames are now always server-generated. - Patches all known-vulnerable dependencies across root/backend/frontend (`npm audit` now clean everywhere), including a critical unauthenticated Next.js RCE (GHSA-9qr9-h5gf-34mp) and moving `express-rate-limit` into `backend/package.json` (it was root-only, so a standalone `cd backend && npm install` never installed it). - Hardening: `jwt.verify()` now pins `algorithms: ['HS256']`; `/uploads` now serves with a restrictive CSP + `X-Content-Type-Options: nosniff` to neutralize SVG-embedded-script XSS. - Version bumped to 1.10.1, tagged `v1.10.1`. ## Test plan - [x] Backend Jest suite (21 tests) passes on the bumped dependencies - [x] Backend boots and serves real HTTP requests on the bumped deps; confirmed CSP/`nosniff` headers present on real uploaded files - [x] `next build` compiles and type-checks cleanly on the bumped frontend deps (verified against a live backend + real event data) - [x] `npm audit` reports 0 vulnerabilities in root, backend, and frontend https://claude.ai/code/session_01CSWFWQsjTc9GyffPiXEDQT
joshua added 2 commits 2026-08-28 12:37:54 +02:00
Path traversal (CWE-22/CWE-73): event-image, branding (logo/favicon),
and event-attachment uploads built the saved filename from the
client-supplied original filename with no sanitization, and multer's
diskStorage joins that straight into the destination path. A crafted
filename containing `../` sequences could write the uploaded file
anywhere the server process has write access — reachable by any
supervisor-level account, and briefly pre-auth via the branding
uploads during initial /setup. Filenames are now always server-
generated (random bytes + validated extension); the original name is
kept only as display metadata.

Dependencies: express-rate-limit was declared only at the repo root
despite being required directly by backend/src/index.js, so a plain
`cd backend && npm install` (per the deployment doc) would never
install it — moved it into backend/package.json. Bumped next off a
version affected by a critical unauthenticated RCE (React Flight
protocol) and switched it from an exact pin to a caret range so future
patches install automatically. Bumped multer/nodemailer/jsonwebtoken/
uuid to patched versions, with an override forcing the vulnerable
nested uuid inside exceljs and the vulnerable postcss bundled inside
next to the patched versions too. `npm audit` is now clean (0
vulnerabilities) across root, backend, and frontend.

Hardening: jwt.verify() now pins algorithms: ['HS256'] instead of
trusting the token header; /uploads now serves with a restrictive CSP
and X-Content-Type-Options: nosniff so an uploaded SVG containing
<script> can't execute if opened directly.

Verified: backend's Jest suite passes, the backend boots and serves
real requests on the bumped deps, and `next build` compiles/type-
checks cleanly on the bumped frontend deps.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CSWFWQsjTc9GyffPiXEDQT
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CSWFWQsjTc9GyffPiXEDQT
joshua merged commit 49b6ddc397 into main 2026-08-28 12:44:22 +02:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: joshua/hope-events#1