Skip to content

fix(ask-ai): reject oversized payloads before parsing to prevent memory exhaustion#502

Closed
anshul23102 wants to merge 1 commit into
knoxiboy:mainfrom
anshul23102:fix/470-image-base64-size-guard
Closed

fix(ask-ai): reject oversized payloads before parsing to prevent memory exhaustion#502
anshul23102 wants to merge 1 commit into
knoxiboy:mainfrom
anshul23102:fix/470-image-base64-size-guard

Conversation

@anshul23102
Copy link
Copy Markdown
Contributor

@anshul23102 anshul23102 commented Jun 2, 2026

User description

Problem Statement

src/app/api/ask-ai/route.ts calls await req.json() without any prior body size check. The imageBase64 field is read entirely into server memory before the imageBase64?.slice(0, 500) truncation at line 516. A single request carrying a multi-megabyte base64 string allocates the full payload on the server heap before any truncation occurs. Under concurrent load, this is a viable path to memory exhaustion.

Current behavior: Any authenticated user can send a request up to the Next.js default body limit (4 MB) and the server will allocate it fully in memory before discarding most of it.

Expected behavior: Oversized requests are rejected before JSON parsing begins.

Root Cause Analysis

The POST handler in route.ts reads the request body unconditionally:

const {
    prompt,
    type = 'standard',
    imageBase64,
    classroomId,
    history = [],
} = await req.json();

The imageBase64 value is only truncated after allocation:

imageBase64?.slice(0, 500),  // truncation happens after full parse

There is no Content-Length guard before this parse, so any body up to the framework default limit passes through.

Solution Overview

Add a Content-Length header check at the top of the POST handler, before req.json() is called. Requests exceeding 512 KB receive a 413 Payload Too Large response immediately, with zero body parsing overhead.

512 KB is generous for all legitimate prompt and history payloads while blocking the multi-megabyte base64 inputs that cause the issue.

Changes Made

src/app/api/ask-ai/route.ts

  • Added MAX_BODY_BYTES constant (512 KB) above the POST export.
  • Added a Content-Length check as the first operation inside the POST handler, before any database access or JSON parsing.
  • Returns 413 with a clear error message when the limit is exceeded.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Performance improvement

Testing Done

Manual Testing Steps

Test Case 1: Normal request

  1. Send a valid POST /api/ask-ai with a prompt under 512 KB.
    Expected: Request proceeds normally, response returned.
    Actual: Passes the guard and reaches existing logic.

Test Case 2: Oversized request

  1. Send a POST /api/ask-ai with a body larger than 512 KB (e.g. a large base64 string).
    Expected: 413 Payload Too Large returned immediately.
    Actual: Guard fires before req.json() is called.

Edge Cases Tested

  • Request with no Content-Length header: parseInt(null ?? '0', 10) evaluates to 0, so the guard does not reject it (the body itself is still bounded by the framework limit).
  • Request exactly at 512 KB: Allowed through.
  • Request at 512 KB + 1 byte: Rejected.

Screenshots or Demo

Not applicable. Server-side JSON parsing guard with no visual component.

Related Issue

Closes #470

Checklist

  • I have read the CONTRIBUTING.md and followed its guidelines
  • My code follows the style and formatting of this project
  • I have tested my changes locally and they work as expected
  • There are no merge conflicts with the base branch
  • This PR is linked to the correct issue
  • I have not used em dashes or double hyphens anywhere
  • No dead code or unreachable statements

GSSoC Label Request

Maintainer, could you please add the appropriate GSSoC label to this PR? This helps with contribution tracking and scoring under GSSoC '26. Thank you!

Summary by CodeRabbit

  • Bug Fixes
    • Improved API endpoint stability by implementing request size validation to prevent oversized requests from consuming excessive memory resources.

CodeAnt-AI Description

Reject oversized ask-ai requests before reading the body

What Changed

  • Requests over 512 KB are now rejected immediately with a 413 response
  • The API checks the request size before any JSON parsing or AI processing starts
  • Users now get a clear error message when their request is too large

Impact

✅ Fewer memory exhaustion crashes
✅ Lower risk of slow ask-ai requests under load
✅ Clearer oversized request errors

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

…ry exhaustion

The imageBase64 field is loaded fully into server memory by req.json() before
the slice(0, 500) truncation. A request with a multi-megabyte body allocates
that full payload on the heap on every call.

Adds a Content-Length guard before req.json() that returns 413 immediately
for payloads above 512 KB, keeping memory usage predictable under load.

Fixes knoxiboy#470
@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented Jun 2, 2026

CodeAnt AI is reviewing your PR.

@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 2, 2026

@anshul23102 is attempting to deploy a commit to the Karan Mani Tripathi 's projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 2, 2026

❌ PR Rejected — Issue Assignment Check Failed

Hi @anshul23102! This PR has been closed because you are not assigned to the issue(s) it references:

What to do:

  1. Comment /assign on the issue to request assignment from a maintainer.
  2. Wait until you are officially assigned.
  3. Then re-open or re-submit your PR.

PRs that fix issues not assigned to the author cannot be accepted — this ensures fair contribution tracking.

@github-actions github-actions Bot requested review from knoxiboy June 2, 2026 03:24
@github-actions github-actions Bot added the invalid This doesn't seem right label Jun 2, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 2, 2026

@coderabbitai review

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 2, 2026

@coderabbitai review

@github-actions github-actions Bot added gssoc'26 GSSoC program issue level:advanced Advanced level task type:bug Bug fix type:feature New feature labels Jun 2, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 2, 2026

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 22b79073-a6d9-456a-a397-a03c2c6c41da

📥 Commits

Reviewing files that changed from the base of the PR and between 99d5b8b and c0aae56.

📒 Files selected for processing (1)
  • src/app/api/ask-ai/route.ts

Walkthrough

This PR adds a defensive request-size check to the ask-ai endpoint. A MAX_BODY_BYTES constant (512 KB) is introduced, and the POST handler now validates the content-length header early, returning a 413 status code if the request exceeds the limit. This prevents large payloads from being parsed into memory.

Changes

Request Size Validation

Layer / File(s) Summary
Request size validation guard
src/app/api/ask-ai/route.ts
MAX_BODY_BYTES constant set to 512 KB. Early content-length header validation in POST handler rejects oversized requests with 413 JSON response before body parsing, preventing unbounded image base64 payloads from being loaded into memory.

🎯 1 (Trivial) | ⏱️ ~3 minutes

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed: dependency version conflict. Check your lock file or package.json.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@codeant-ai codeant-ai Bot added the size:S This PR changes 10-29 lines, ignoring generated files label Jun 2, 2026
@github-actions github-actions Bot added size/s and removed size:S This PR changes 10-29 lines, ignoring generated files size/xs labels Jun 2, 2026
Comment on lines +211 to +212
const contentLength = parseInt(req.headers.get('content-length') ?? '0', 10);
if (contentLength > MAX_BODY_BYTES) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: This size guard trusts the client-supplied Content-Length header, so a request sent with chunked transfer encoding (no Content-Length) or a missing header bypasses the check and still reaches req.json(), allowing large bodies to be fully buffered in memory. Enforce the limit based on actual bytes read from the request stream (or reject requests without a valid length for this endpoint) so oversized payloads cannot bypass the protection. [security]

Severity Level: Major ⚠️
- ❌ /api/ask-ai accepts >512 KB bodies via chunked.
- ❌ Memory usage spikes when large chunked bodies parsed.
- ⚠️ 512 KB limit ineffective against crafted HTTP clients.
Steps of Reproduction ✅
1. Start the DoubtDesk application so the Next.js API route implemented in
`src/app/api/ask-ai/route.ts` is served; this route defines `export async function
POST(req: Request)` with the `contentLength` guard at approximately lines 32–38 (as seen
in the file content).

2. From a custom HTTP client (e.g., `nc`, `telnet`, or a raw Node.js `net` socket), send
an HTTP/1.1 request to `POST /api/ask-ai` with headers including `Transfer-Encoding:
chunked` and **no `Content-Length` header**, and a JSON body larger than 512 KB (for
example, a large `imageBase64` string) so that the request remains under the framework's
global 4 MB limit but above `MAX_BODY_BYTES`.

3. On the server, the POST handler at `src/app/api/ask-ai/route.ts` executes the guard
`const contentLength = parseInt(req.headers.get('content-length') ?? '0', 10);` followed
by `if (contentLength > MAX_BODY_BYTES) { ... }`. Because the request is chunked and omits
`Content-Length`, `req.headers.get('content-length')` returns `null`, `parseInt('0', 10)`
yields `0`, and the `if (contentLength > MAX_BODY_BYTES)` condition at lines 211–212
evaluates to `false`, so the 413 response is not triggered.

4. Execution continues into the rest of the POST handler, which later calls `await
req.json()` to parse the request body; this causes the full >512 KB JSON payload
(including the large `imageBase64` field) to be read and buffered into memory, bypassing
the intended size restriction and allowing repeated large requests to consume significant
heap memory under concurrent load.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/app/api/ask-ai/route.ts
**Line:** 211:212
**Comment:**
	*Security: This size guard trusts the client-supplied `Content-Length` header, so a request sent with chunked transfer encoding (no `Content-Length`) or a missing header bypasses the check and still reaches `req.json()`, allowing large bodies to be fully buffered in memory. Enforce the limit based on actual bytes read from the request stream (or reject requests without a valid length for this endpoint) so oversized payloads cannot bypass the protection.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines +205 to +215
const MAX_BODY_BYTES = 512 * 1024; // 512 KB

export async function POST(req: Request) {
try {
// Reject oversized payloads before parsing JSON to avoid loading
// a multi-megabyte body into memory only to discard most of it.
const contentLength = parseInt(req.headers.get('content-length') ?? '0', 10);
if (contentLength > MAX_BODY_BYTES) {
return NextResponse.json(
{ error: 'Request payload too large. Maximum size is 512 KB.' },
{ status: 413 }
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 Architect Review — HIGH

The new 512 KB server-side body limit for /api/ask-ai reduces the maximum accepted image payload well below what the Ask AI UI promises ("Max 10MB") and below what the client currently enforces, so typical camera-sized uploads that previously worked will now be rejected with 413 while the UI still suggests larger files are acceptable.

Suggestion: Align the backend limit with the product flow by either increasing the server limit or, if 512 KB is required, adding client-side file-size enforcement/compression plus updated UX copy and explicit handling of 413 responses in src/app/ask-ai/page.tsx so users are warned before upload and see a clear size-related error.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is an **Architect / Logical Review** comment left during a code review. These reviews are first-class, important findings — not optional suggestions. Do NOT dismiss this as a 'big architectural change' just because the title says architect review; most of these can be resolved with a small, localized fix once the intent is understood.

**Path:** src/app/api/ask-ai/route.ts
**Line:** 205:215
**Comment:**
	*HIGH: The new 512 KB server-side body limit for /api/ask-ai reduces the maximum accepted image payload well below what the Ask AI UI promises ("Max 10MB") and below what the client currently enforces, so typical camera-sized uploads that previously worked will now be rejected with 413 while the UI still suggests larger files are acceptable.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
If a suggested approach is provided above, use it as the authoritative instruction. If no explicit code suggestion is given, you MUST still draft and apply your own minimal, localized fix — do not punt back with 'no suggestion provided, review manually'. Keep the change as small as possible: add a guard clause, gate on a loading state, reorder an await, wrap in a conditional, etc. Do not refactor surrounding code or expand scope beyond the finding.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix

@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented Jun 2, 2026

CodeAnt AI finished reviewing your PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gssoc'26 GSSoC program issue invalid This doesn't seem right level:advanced Advanced level task review-needed size/s type:bug Bug fix type:feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Unbounded image base64 payload loaded entirely into memory before truncation in ask-ai route

1 participant