Image processing has output dimension limits
Why it matters
Image processing libraries like Sharp allocate memory proportional to output pixel area — a request for a 999,999 × 999,999 image allocates roughly 3 TB of virtual memory, which OOMs the Node process instantly. This is CWE-770 and CWE-400 in the same request: resource exhaustion via unconstrained user input. Any endpoint that accepts width and height from a query string or POST body without validation is a denial-of-service vector with zero authentication required. OWASP A05:2021 (Security Misconfiguration) covers this class of missing input constraint. Even modest abuse — thousands of 4000×4000 requests — can exhaust CPU and inflate cloud egress for legitimate users.
Severity rationale
High because a single crafted request with extreme dimensions can OOM the Node process, taking down the entire application for all users.
Remediation
Validate width and height against a Zod schema with a hard .max() before any Sharp call. Reject the request before the buffer is even allocated.
import { z } from 'zod'
import sharp from 'sharp'
const ResizeSchema = z.object({
width: z.number().int().min(1).max(2000),
height: z.number().int().min(1).max(2000),
})
export async function POST(req: Request) {
const { width, height } = ResizeSchema.parse(await req.json())
const buffer = await req.arrayBuffer()
const output = await sharp(Buffer.from(buffer))
.resize(width, height)
.webp({ quality: 80 })
.toBuffer()
return new Response(output, { headers: { 'Content-Type': 'image/webp' } })
}
Choose a sensible max for your product — 2000px is generous for thumbnails, 4000px for user-uploaded cover images.
Detection
-
ID:
image-processing-dimension-limit -
Severity:
high -
What to look for: When an image processing library is in
package.jsondependencies (sharp,jimp,image-size,@squoosh/lib,gm,imagemagick), count all image processing call sites:.resize(,.extract(,.composite(,.png(,.jpeg(,.webp(,.toFormat(. For each call site, before evaluating, extract and quote the size argument or the surrounding validation. Verify the operation occurs inside a function whose width/height parameters are validated against a maximum (look forMath.min(width, MAX_WIDTH),if (width > X),z.number().max(X), schema-based validation, or a hardcoded literal width/height). -
Pass criteria: 100% of image processing call sites have dimension validation OR use a hardcoded constant size. Report: "X image processing call sites inspected, Y validated, 0 unvalidated."
-
Fail criteria: At least 1 image processing call uses width/height from user input without validation.
-
Skip (N/A) when: No image processing library in dependencies.
-
Detail on fail:
"1 unvalidated image resize: sharp(buffer).resize(req.body.width, req.body.height) in app/api/thumbnail/route.ts — user can request 999999x999999 image, exhausting memory" -
Remediation: Sharp can allocate gigabytes of memory for a single oversized image — one user with
width=999999&height=999999can OOM your server. Validate dimensions:import { z } from 'zod' import sharp from 'sharp' const ResizeSchema = z.object({ width: z.number().int().min(1).max(2000), height: z.number().int().min(1).max(2000), }) export async function POST(req: Request) { const { width, height } = ResizeSchema.parse(await req.json()) const buffer = await req.arrayBuffer() const result = await sharp(Buffer.from(buffer)).resize(width, height).png().toBuffer() return new Response(result, { headers: { 'Content-Type': 'image/png' } }) }
External references
- cwe · CWE-400 — Uncontrolled Resource Consumption
- cwe · CWE-770 — Allocation of Resources Without Limits or Throttling
- owasp:2021 · A05
Taxons
History
- 2026-04-18·v1.0.0·Initial import from ai-slop-cost-bombs·automated