Task: Harden File Upload Validation on AWS S3 Endpoints #352

Open
opened 2026-02-28 00:18:28 +00:00 by jjalangtry · 0 comments
jjalangtry commented 2026-02-28 00:18:28 +00:00 (Migrated from github.com)

Harden File Upload Validation on AWS S3 Endpoints

Description

The profile picture upload endpoint (next/app/api/aws/profilePictures/route.ts) checks contentType.startsWith("image/") to validate uploads, but Content-Type is a client-supplied header that can be forged. This allows an attacker to upload arbitrary files (scripts, HTML, SVGs with embedded JS) by spoofing the header. Server-side validation must be used instead.

Associated Epic: #346

Subtasks

  • Audit next/app/api/aws/profilePictures/route.ts and next/app/api/aws/officerPictures/route.ts for current validation logic
  • Replace the Content-Type header check with an explicit allowlist: only image/jpeg, image/png, image/webp, and image/gif are accepted
  • Read the first few bytes of the uploaded file (magic bytes) to verify the actual file type matches the declared type — do not rely solely on the Content-Type header
  • Enforce a maximum file size (recommended: 5 MB for profile pictures, 10 MB for officer pictures)
  • Sanitize the filename: strip path separators, limit to alphanumeric + extension, or replace with a UUID entirely
  • Reject SVG uploads explicitly (SVG can contain embedded JavaScript)
  • Return 415 Unsupported Media Type for disallowed file types, 413 Payload Too Large for oversized files

Acceptance Criteria

  • Uploading a .html file with Content-Type: image/jpeg returns 415
  • Uploading an SVG returns 415
  • Uploading a file larger than the size limit returns 413
  • Uploading a valid JPEG under the size limit succeeds
  • The stored S3 object key does not contain user-supplied path components
# Harden File Upload Validation on AWS S3 Endpoints ## Description The profile picture upload endpoint (next/app/api/aws/profilePictures/route.ts) checks contentType.startsWith("image/") to validate uploads, but Content-Type is a client-supplied header that can be forged. This allows an attacker to upload arbitrary files (scripts, HTML, SVGs with embedded JS) by spoofing the header. Server-side validation must be used instead. Associated Epic: #346 ## Subtasks - [ ] Audit next/app/api/aws/profilePictures/route.ts and next/app/api/aws/officerPictures/route.ts for current validation logic - [ ] Replace the Content-Type header check with an explicit allowlist: only image/jpeg, image/png, image/webp, and image/gif are accepted - [ ] Read the first few bytes of the uploaded file (magic bytes) to verify the actual file type matches the declared type — do not rely solely on the Content-Type header - [ ] Enforce a maximum file size (recommended: 5 MB for profile pictures, 10 MB for officer pictures) - [ ] Sanitize the filename: strip path separators, limit to alphanumeric + extension, or replace with a UUID entirely - [ ] Reject SVG uploads explicitly (SVG can contain embedded JavaScript) - [ ] Return 415 Unsupported Media Type for disallowed file types, 413 Payload Too Large for oversized files ## Acceptance Criteria - [ ] Uploading a .html file with Content-Type: image/jpeg returns 415 - [ ] Uploading an SVG returns 415 - [ ] Uploading a file larger than the size limit returns 413 - [ ] Uploading a valid JPEG under the size limit succeeds - [ ] The stored S3 object key does not contain user-supplied path components
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
SSE/WebsiteTheSSEquel#352
No description provided.