Skip to content

Fix Memory Exhaustion and DoS for PDF uploads (#1549) - #1550

Open
Dev1822 wants to merge 4 commits into
Canopus-Labs:mainfrom
Dev1822:fix-multer-memory-dos-1549
Open

Fix Memory Exhaustion and DoS for PDF uploads (#1549)#1550
Dev1822 wants to merge 4 commits into
Canopus-Labs:mainfrom
Dev1822:fix-multer-memory-dos-1549

Conversation

@Dev1822

@Dev1822 Dev1822 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

📝 Pull Request Description

Related Issue

Closes #1549

Summary

This PR fixes a critical Denial of Service (DoS) vulnerability caused by memory exhaustion during large PDF uploads.

The uploadNotes and uploadResume multer middlewares were previously configured to use memoryStorage(), which buffered the entire file into Node.js RAM before reaching the route controllers. This allowed attackers to crash the server by sending multiple concurrent 15MB file uploads, quickly exceeding the Node.js heap limit.

We have migrated these upload handlers to use diskStorage() instead. The files are now streamed to an uploads/ directory during the request, keeping the memory footprint low and predictable. The route controllers (notesSummaryController and resumeController) have been updated to securely read the file from disk, process it with the Gemini API, and clean up (delete) the temporary file immediately afterward in a finally block to prevent disk space leaks.


Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature
  • ♻️ Refactoring
  • 📝 Documentation update
  • 🎨 UI/UX improvement
  • 🔥 Other(please describe) ______

How Has This Been Tested?

  • Verified that concurrent large PDF uploads no longer spike Node.js RAM usage (mitigating the DoS vulnerability).
  • Verified that PDF notes continue to be correctly processed and summarized by the Gemini API.
  • Verified that resume PDFs continue to be correctly processed and analyzed by the Gemini API.
  • Verified that temporary files in the uploads/ directory are successfully deleted after processing completes, regardless of success or failure.

Screenshots (if applicable)

N/A


Checklist

  • My code follows the project's guidelines
  • I have tested my changes
  • I have updated documentation where necessary
  • I have linked the related issue
  • My changes do not introduce new warnings or errors

Summary

Replaces Multer memory storage with disk storage for PDF uploads. This prevents large concurrent uploads from exhausting Node.js memory.

The controllers process uploaded PDFs from disk and delete temporary files after successful or failed processing.

Image uploads continue to use memory storage.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Dev1822, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 19 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fbecbfd3-c6d3-410f-b93b-1d0ed4d13d80

📥 Commits

Reviewing files that changed from the base of the PR and between dc3ea2d and 2759ba2.

📒 Files selected for processing (2)
  • backend/Input_validators/ValidateNotesSummary.js
  • backend/Input_validators/ValidateResume.js
📝 Walkthrough

Walkthrough

Resume and notes PDF uploads now use temporary disk storage. Validation accepts PDF files from disk, controllers read and Base64-encode file contents, and cleanup runs after processing or validation failure.

Changes

PDF upload processing

Layer / File(s) Summary
Disk storage and file validation
backend/middlewares/uploadMiddleware.js
Resume and notes uploads use random .pdf filenames in the system temporary directory. Validation supports buffers and file paths, accepts PDF content, and removes invalid temporary files.
Controller file lifecycle
backend/controllers/notesSummaryController.js, backend/controllers/resumeController.js
Controllers read PDFs from disk, prepare Base64 payloads, release buffer references, and delete temporary files after processing.
Validation failure cleanup
backend/Input_validators/ValidateNotesSummary.js, backend/Input_validators/ValidateResume.js
Validators remove uploaded temporary files when schema validation fails.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant uploadMiddleware
  participant Controller
  participant Filesystem
  participant Gemini

  Client->>uploadMiddleware: Upload PDF
  uploadMiddleware->>Filesystem: Store temporary PDF
  uploadMiddleware->>Controller: Pass temporary file path
  Controller->>Filesystem: Read PDF
  Filesystem-->>Controller: Return PDF buffer
  Controller->>Gemini: Send Base64 PDF content
  Controller->>Filesystem: Delete temporary PDF
Loading

Possibly related PRs

  • Canopus-Labs/PrepPilot#1525: Both changes modify summarizeNotes, but this PR adds disk-backed PDF handling while that PR adds content-hash caching.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the primary change: fixing memory exhaustion and DoS risks for PDF uploads.
Linked Issues check ✅ Passed The changes replace Multer memory storage with disk storage for PDF uploads and add processing cleanup, meeting issue #1549 objectives.
Out of Scope Changes check ✅ Passed The changes remain within issue #1549 by addressing upload storage, validation cleanup, file processing, and temporary-file removal.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

Comment thread backend/controllers/notesSummaryController.js Fixed
Comment thread backend/controllers/resumeController.js Fixed
Comment thread backend/controllers/resumeController.js Fixed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
backend/middlewares/uploadMiddleware.js (1)

161-166: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Remove the unreachable Word MIME types from validateResumeMagicBytes.

resumeFileFilter rejects Word uploads before the validator runs, so accepted files are consistently stored and sent to Gemini as PDFs. The current Word allowlist and error message are misleading.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/middlewares/uploadMiddleware.js` around lines 161 - 166, Update
validateResumeMagicBytes to remove the unreachable Word MIME types from its
allowlist and revise its error message to describe only supported PDF files;
leave resumeFileFilter and the PDF upload flow unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/controllers/notesSummaryController.js`:
- Around line 244-247: Extend temporary-file cleanup beyond the controller
finally blocks so files are removed when validation middleware short-circuits:
update backend/controllers/notesSummaryController.js lines 244-247 around
summarizeNotes/validateSummarizeNotes, and
backend/controllers/resumeController.js lines 169-172 around
analyzeResume/validateResumeMagicBytes/validateAnalyzeResume. Ensure each
uploaded temporary file is deleted exactly once across both validation-error and
normal post-upload paths, preserving the existing error handling for unlink
failures.
- Around line 114-116: Bound PDF memory usage in notesSummaryController.js
(lines 114-116) and resumeController.js (lines 110-112 and 141) by using Gemini
file-based input or acquiring a shared byte/concurrency budget before each
fs.promises.readFile call and releasing it in finally; ensure the full Buffer
and base64 representations are not simultaneously retained without this bound.

In `@backend/middlewares/uploadMiddleware.js`:
- Around line 161-166: Update the filename callbacks in both upload storage
instances, including uploadResume, to generate a server-side unique temporary
filename for every upload rather than combining Date.now() with
sanitizeBase(file.originalname). Keep file.originalname available only as
metadata and preserve the .pdf extension.
- Around line 161-166: Update the upload storage configuration around
uploadResume and the corresponding notes Multer instance so resumes and notes
are stored outside the directory exposed by express.static; keep profile images
in a separately served public location. Ensure rejected uploads are deleted
during validation, and make cleanup failures propagate or otherwise receive
explicit handling beyond logging.

---

Nitpick comments:
In `@backend/middlewares/uploadMiddleware.js`:
- Around line 161-166: Update validateResumeMagicBytes to remove the unreachable
Word MIME types from its allowlist and revise its error message to describe only
supported PDF files; leave resumeFileFilter and the PDF upload flow unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4e110586-4bca-498a-bc1c-c4f9d9382df1

📥 Commits

Reviewing files that changed from the base of the PR and between 4ba01aa and b1bb2d8.

📒 Files selected for processing (3)
  • backend/controllers/notesSummaryController.js
  • backend/controllers/resumeController.js
  • backend/middlewares/uploadMiddleware.js

Comment thread backend/controllers/notesSummaryController.js
Comment on lines +244 to +247
} finally {
if (uploadedFilePath) {
fs.promises.unlink(uploadedFilePath).catch(err => console.error("Failed to delete temp notes PDF:", err));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Make temporary-file cleanup cover the complete post-upload lifecycle.

The controller finally blocks do not run when earlier route middleware returns a validation error. Those files remain on disk and can create a disk-exhaustion DoS.

  • backend/controllers/notesSummaryController.js#L244-L247: clean the file when validateSummarizeNotes short-circuits before summarizeNotes.
  • backend/controllers/resumeController.js#L169-L172: clean the file when validateResumeMagicBytes or validateAnalyzeResume short-circuits before analyzeResume.
📍 Affects 2 files
  • backend/controllers/notesSummaryController.js#L244-L247 (this comment)
  • backend/controllers/resumeController.js#L169-L172
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/controllers/notesSummaryController.js` around lines 244 - 247, Extend
temporary-file cleanup beyond the controller finally blocks so files are removed
when validation middleware short-circuits: update
backend/controllers/notesSummaryController.js lines 244-247 around
summarizeNotes/validateSummarizeNotes, and
backend/controllers/resumeController.js lines 169-172 around
analyzeResume/validateResumeMagicBytes/validateAnalyzeResume. Ensure each
uploaded temporary file is deleted exactly once across both validation-error and
normal post-upload paths, preserving the existing error handling for unlink
failures.

Comment thread backend/middlewares/uploadMiddleware.js
Comment thread backend/Input_validators/ValidateNotesSummary.js Fixed
Comment thread backend/Input_validators/ValidateNotesSummary.js Fixed
Comment thread backend/Input_validators/ValidateResume.js Fixed
Comment thread backend/Input_validators/ValidateResume.js Fixed
Comment thread backend/middlewares/uploadMiddleware.js Fixed
Comment thread backend/middlewares/uploadMiddleware.js Fixed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/controllers/resumeController.js (1)

172-175: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Await and harden temporary-file cleanup.

unlink() is started but not awaited. The request can complete before deletion finishes, and deletion failures only produce a log entry. Persistent failures can accumulate PDFs in temporary storage and exhaust disk space. Await cleanup in finally, and add bounded retries or a TTL-based janitor for files that remain.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/controllers/resumeController.js` around lines 172 - 175, Update the
finally cleanup in the resume controller to await deletion of uploadedFilePath
before the request completes, and add bounded retry handling or an existing
TTL-based janitor for files that cannot be removed. Preserve cleanup only when
uploadedFilePath is present, and ensure persistent failures remain visible
without leaving unbounded temporary files.
♻️ Duplicate comments (1)
backend/controllers/notesSummaryController.js (1)

114-116: ⚠️ Potential issue | 🟠 Major

Bound active PDF-processing memory, not only upload memory.

Line 116 still reads the complete PDF into memory. Lines 145-147 then retain a second Base64 representation before releasing buffer. At the 15 MiB limit, the two representations use roughly 35 MiB per active request before parser and Gemini overhead. Unless a separate global budget exists, the per-IP limiter does not bound concurrent memory usage. Use Gemini file-based input or a shared byte/concurrency budget around readFile.

#!/bin/bash
set -euo pipefail

rg -n -C 8 \
  'aiLimiter|readFile|inlineData|base64|Semaphore|p-limit|concurr|active|budget' \
  backend --glob '*.js'

Also applies to: 145-147, 177-177

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/controllers/notesSummaryController.js` around lines 114 - 116, Change
the PDF processing flow in the notes summary controller around the upload read
and subsequent Base64/inlineData handling so it does not retain multiple
full-file representations per request. Prefer Gemini file-based input; otherwise
wrap readFile and related processing in an existing shared byte/concurrency
budget, ensuring the budget covers the full active processing interval and is
released on every path.
🧹 Nitpick comments (1)
backend/Input_validators/ValidateNotesSummary.js (1)

31-31: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Remove the unreachable uploaded-file cleanup checks.

Both checks run only after the code has established that req.file is absent. They cannot delete a temporary upload.

  • backend/Input_validators/ValidateNotesSummary.js#L31-L31: remove the dead check from the missing-source branch.
  • backend/Input_validators/ValidateResume.js#L53-L53: remove the dead check from the no-resume branch.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/Input_validators/ValidateNotesSummary.js` at line 31, Remove the
unreachable uploaded-file cleanup checks from the missing-source branch in
backend/Input_validators/ValidateNotesSummary.js (line 31) and the no-resume
branch in backend/Input_validators/ValidateResume.js (line 53). No other
behavior in these validation branches needs to change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/controllers/resumeController.js`:
- Around line 111-116: Update uploadResume so concurrent resume analyses are
bounded before fs.promises.readFile() allocates the file Buffer and Base64
string; use supported file-backed or streaming Gemini input when available,
otherwise acquire an in-flight concurrency slot before readFile() and release it
in all success and error paths. Do not rely on aiLimiter, which only limits
hourly request volume.

In `@backend/Input_validators/ValidateNotesSummary.js`:
- Line 39: Update the temporary-file cleanup in ValidateNotesSummary.js:39-39
and ValidateResume.js:58-58 to ignore unlink failures only when the error code
is ENOENT, while logging or reporting all other errors. Apply the same handling
to both handlers and preserve cleanup execution when req.file.path is present.

In `@backend/middlewares/uploadMiddleware.js`:
- Line 137: Update the temporary-file cleanup calls in the upload middleware at
both `req.file.path` deletion sites to record unlink failures instead of
silently discarding them. Preserve the existing response status and cleanup
flow, but log or otherwise report the caught error through the middleware’s
established observability mechanism.
- Around line 4-6: Replace the CommonJS file-type destructuring in
uploadMiddleware with a dynamic import("file-type"), then update every call site
using fileTypeFromBuffer or fileTypeFromFile to access the dynamically loaded
module’s exports while preserving their existing behavior.

---

Outside diff comments:
In `@backend/controllers/resumeController.js`:
- Around line 172-175: Update the finally cleanup in the resume controller to
await deletion of uploadedFilePath before the request completes, and add bounded
retry handling or an existing TTL-based janitor for files that cannot be
removed. Preserve cleanup only when uploadedFilePath is present, and ensure
persistent failures remain visible without leaving unbounded temporary files.

---

Duplicate comments:
In `@backend/controllers/notesSummaryController.js`:
- Around line 114-116: Change the PDF processing flow in the notes summary
controller around the upload read and subsequent Base64/inlineData handling so
it does not retain multiple full-file representations per request. Prefer Gemini
file-based input; otherwise wrap readFile and related processing in an existing
shared byte/concurrency budget, ensuring the budget covers the full active
processing interval and is released on every path.

---

Nitpick comments:
In `@backend/Input_validators/ValidateNotesSummary.js`:
- Line 31: Remove the unreachable uploaded-file cleanup checks from the
missing-source branch in backend/Input_validators/ValidateNotesSummary.js (line
31) and the no-resume branch in backend/Input_validators/ValidateResume.js (line
53). No other behavior in these validation branches needs to change.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b48ae651-9cc9-417f-a4b1-255be52aec48

📥 Commits

Reviewing files that changed from the base of the PR and between b1bb2d8 and 9ca5b8a.

📒 Files selected for processing (5)
  • backend/Input_validators/ValidateNotesSummary.js
  • backend/Input_validators/ValidateResume.js
  • backend/controllers/notesSummaryController.js
  • backend/controllers/resumeController.js
  • backend/middlewares/uploadMiddleware.js

Comment on lines +111 to +116
let fileBuffer = await fs.promises.readFile(uploadedFilePath);

const targetRole = req.body.targetRole || "General Professional";

const base64Data = fileBuffer.toString("base64");
fileBuffer = null; // Release Buffer memory

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 Performance & Scalability | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n -C 6 'readFile|inlineData|uploadFile|fileSize|uploadResume|uploadNotes' backend

Repository: Canopus-Labs/PrepPilot

Length of output: 15047


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- upload limits and resume route ---'
sed -n '1,210p' backend/middlewares/uploadMiddleware.js
sed -n '1,80p' backend/routes/resumeRoutes.js

printf '%s\n' '--- resume controller and fallback helper references ---'
sed -n '90,165p' backend/controllers/resumeController.js
rg -n -C 8 'function generateWithFallback|const generateWithFallback|generateWithFallback|aiLimiter' backend

Repository: Canopus-Labs/PrepPilot

Length of output: 38065


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- fallback implementation ---'
sed -n '1,120p' backend/utils/geminiHelper.js

printf '%s\n' '--- controller cleanup and response path ---'
sed -n '150,245p' backend/controllers/resumeController.js

printf '%s\n' '--- exact memory multipliers at the configured resume limit ---'
python3 - <<'PY'
size = 5 * 1024 * 1024
base64_size = 4 * ((size + 2) // 3)
print({
    "resume_limit_bytes": size,
    "base64_bytes": base64_size,
    "peak_buffer_plus_base64_bytes": size + base64_size,
    "peak_buffer_plus_base64_mib": (size + base64_size) / (1024 * 1024),
    "peak_for_15_concurrent_uploads_mib": 15 * (size + base64_size) / (1024 * 1024),
})
PY

Repository: Canopus-Labs/PrepPilot

Length of output: 7990


Bound concurrent resume analyses before readFile().

uploadResume limits resumes to 5 MiB, not 15 MiB. Each active request can retain about 11.67 MiB for the Buffer and Base64 string, so 15 concurrent requests can retain about 175 MiB before SDK overhead. aiLimiter limits requests per hour, not in-flight analyses. Use file-backed or streaming Gemini input when supported; otherwise add a concurrency limit before readFile().

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/controllers/resumeController.js` around lines 111 - 116, Update
uploadResume so concurrent resume analyses are bounded before
fs.promises.readFile() allocates the file Buffer and Base64 string; use
supported file-backed or streaming Gemini input when available, otherwise
acquire an in-flight concurrency slot before readFile() and release it in all
success and error paths. Do not rely on aiLimiter, which only limits hourly
request volume.

Comment thread backend/Input_validators/ValidateNotesSummary.js Outdated
Comment thread backend/middlewares/uploadMiddleware.js Outdated
Comment thread backend/middlewares/uploadMiddleware.js Outdated
…ean validation paths, dynamic file-type import

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/Input_validators/ValidateNotesSummary.js`:
- Line 40: Make validateSummarizeNotes in
backend/Input_validators/ValidateNotesSummary.js asynchronous and await unlink
cleanup before calling handleValidationError. Apply the same change to
validateAnalyzeResume at backend/Input_validators/ValidateResume.js, ensuring
each validation response is sent only after deletion settles.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e2f85e59-b9b3-4cde-b170-fa4cd3a659c1

📥 Commits

Reviewing files that changed from the base of the PR and between 9ca5b8a and dc3ea2d.

📒 Files selected for processing (5)
  • backend/Input_validators/ValidateNotesSummary.js
  • backend/Input_validators/ValidateResume.js
  • backend/controllers/notesSummaryController.js
  • backend/controllers/resumeController.js
  • backend/middlewares/uploadMiddleware.js
🚧 Files skipped from review as they are similar to previous changes (3)
  • backend/controllers/notesSummaryController.js
  • backend/controllers/resumeController.js
  • backend/middlewares/uploadMiddleware.js

Comment thread backend/Input_validators/ValidateNotesSummary.js Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: multer.memoryStorage() for 15MB PDF uploads causes Memory Exhaustion and DoS

2 participants