Profile image upload has no file size limit
The profile image upload handler validates MIME via magic number and uses an opaque filename, but enforces no size limit before buffering and writing the file to a publicly served directory.
The handler in profileImageFileUpload() reads req.file.buffer (multer memory storage) and passes it to fs.writeFile at frontend/dist/frontend/assets/public/images/uploads/${loggedInUser.data.id}.${uploadedFileType.ext}. The file is then linked from the user's profileImage column and served as a static asset.
Validation present:
- Magic‑number/MIME check via
file-type.fromBufferplus astartsWith('image')allowlist. - Opaque storage path (filename is the user id, not
originalname), defeating path traversal and double‑extension tricks.
Validation missing:
- No per‑file size cap is set in this handler, and the file is fully buffered in memory (
req.file.buffer) before being written. Without amulter({ limits: { fileSize: ... } })configuration on the route, an authenticated attacker can submit arbitrarily large payloads and either fill the disk underfrontend/dist/frontend/assets/public/images/uploads/or exhaust Node process memory while the buffer is held.
Because the uploaded artifact is subsequently served as a static asset, the criteria for flagging a single missing control (size limit) are met.
Note: the image/* allowlist still admits image/svg+xml if file-type recognises it, which would be stored XSS when fetched from the assets path — but the primary, certain issue here is the missing size/quantity limit.
const filePath = `frontend/dist/frontend/assets/public/images/uploads/${loggedInUser.data.id}.${uploadedFileType.ext}`
try {
await fs.writeFile(filePath, buffer)
} catch (err) { ... }- Authenticate and obtain a session cookie/token.
- POST a multipart/form-data request to the profile-image endpoint where the
filepart is a very large (e.g., several GB) buffer whose first bytes are a valid PNG magic header followed by junk:
printf '\x89PNG\r\n\x1a\n' > big.png && dd if=/dev/zero bs=1M count=5000 >> big.png curl -b token=$T -F file=@big.png http://target/profile/image/file
- The server buffers the whole body in memory and writes it under
frontend/dist/frontend/assets/public/images/uploads/<userId>.png. Repeating the request (or sending one large request per user) exhausts disk and/or Node heap.
Authenticated users can cause denial of service via disk exhaustion (files are written to a static asset directory that is also part of the built frontend) and memory pressure (multer memory storage holds the entire upload in RAM before the write). No size or request-rate guard exists on this handler.
Size limits for multer-based uploads are configured on the middleware at route registration (e.g., multer({ limits: { fileSize: ... } })), not inside the handler shown. The detector's claim "no size limit" is based on the absence of such config in this file, but the relevant config lives in the route/server setup file, which was not examined or quoted. Without inspecting the route mount for profileImageFileUpload(), the assertion that there is no limits.fileSize is unproven, and the PoC's assumption that multer will buffer GBs of data cannot be validated. Verdict is uncertain.
The endpoint is reachable over HTTP (AV:N) and requires only an authenticated session — security.authenticatedUsers.get(req.cookies.token) is checked but any logged-in user qualifies (PR:L). No race or special preconditions are needed (AC:L) and no victim action is required (UI:N). The handler accepts req.file.buffer from multer memory storage and calls fs.writeFile with no limits.fileSize configuration, so an attacker can submit arbitrarily large uploads to exhaust Node heap and/or fill the disk under frontend/dist/.../uploads/, yielding sustained denial of service (A:H). No confidentiality or integrity impact is demonstrated by the missing size-limit issue itself, and the impact stays within the same Node application (S:U).
- CWE-434
- CWE-400
- CWE-770
- OWASP A04:2021 — Insecure Design