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
66 lines
1.8 KiB
JSON
66 lines
1.8 KiB
JSON
{
|
|
"name": "hope-events-frontend",
|
|
"version": "1.10.0",
|
|
"private": true,
|
|
"scripts": {
|
|
"dev": "next dev --turbopack",
|
|
"build": "next build",
|
|
"start": "next start",
|
|
"lint": "next lint"
|
|
},
|
|
"dependencies": {
|
|
"@hookform/resolvers": "^5.2.1",
|
|
"@radix-ui/react-accordion": "^1.2.11",
|
|
"@radix-ui/react-alert-dialog": "^1.1.14",
|
|
"@radix-ui/react-avatar": "^1.1.10",
|
|
"@radix-ui/react-checkbox": "^1.3.2",
|
|
"@radix-ui/react-dialog": "^1.1.14",
|
|
"@radix-ui/react-dropdown-menu": "^2.1.15",
|
|
"@radix-ui/react-label": "^2.1.7",
|
|
"@radix-ui/react-navigation-menu": "^1.2.13",
|
|
"@radix-ui/react-radio-group": "^1.3.7",
|
|
"@radix-ui/react-select": "^2.2.5",
|
|
"@radix-ui/react-separator": "^1.1.7",
|
|
"@radix-ui/react-slider": "^1.3.5",
|
|
"@radix-ui/react-slot": "^1.2.3",
|
|
"@radix-ui/react-switch": "^1.2.5",
|
|
"@radix-ui/react-tabs": "^1.1.12",
|
|
"@radix-ui/react-toast": "^1.2.14",
|
|
"@radix-ui/react-tooltip": "^1.2.7",
|
|
"@sentry/nextjs": "^10.71.0",
|
|
"@zxing/browser": "^0.1.5",
|
|
"class-variance-authority": "^0.7.1",
|
|
"clsx": "^2.1.1",
|
|
"date-fns": "^4.1.0",
|
|
"lucide-react": "^0.536.0",
|
|
"next": "^15.5.24",
|
|
"qrcode": "^1.5.4",
|
|
"react": "19.1.0",
|
|
"react-day-picker": "^9.8.1",
|
|
"react-dom": "19.1.0",
|
|
"react-hook-form": "^7.62.0",
|
|
"react-webcam": "^7.2.0",
|
|
"tailwind-merge": "^3.3.1",
|
|
"tailwindcss-animate": "^1.0.7",
|
|
"zod": "^4.0.15"
|
|
},
|
|
"devDependencies": {
|
|
"@eslint/eslintrc": "^3",
|
|
"@types/node": "^20",
|
|
"@types/qrcode": "^1.5.5",
|
|
"@types/react": "^19",
|
|
"@types/react-dom": "^19",
|
|
"autoprefixer": "^10.4.21",
|
|
"eslint": "^9",
|
|
"eslint-config-next": "^15.5.24",
|
|
"postcss": "^8.5.6",
|
|
"tailwindcss": "3.4",
|
|
"typescript": "^5"
|
|
},
|
|
"overrides": {
|
|
"next": {
|
|
"postcss": "^8.5.23"
|
|
}
|
|
}
|
|
}
|