Skip to content

Don't read uploaded files during request validation - #494

Merged
ahx merged 1 commit into
mainfrom
dont-load-binary-file-uploads
Aug 12, 2026
Merged

Don't read uploaded files during request validation#494
ahx merged 1 commit into
mainfrom
dont-load-binary-file-uploads

Conversation

@ahx

@ahx ahx commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Every multipart/form-data part that arrived as a file was read into memory in full before the request body was validated. Request validation runs before any application or authentication code, so one large upload to any documented multipart route could grow the process heap proportionally to the upload and get it OOM-killed. Reading the file bought nothing: content of a format: binary field is accepted as is.

Such a part is now passed through as Rack parsed it ({ filename:, type:, name:, tempfile:, head: }) — the same shape Sinatra and Hanami hand to an app — and it is validated as an empty binary String, so type: string, format: binary and required keep working.

Breaking: parsed_body['file'] is the part instead of the file content. Use parsed_body['file'][:tempfile] to read or stream it.

Known limitations, all in the CHANGELOG:

  • Content constraints (minLength, maxLength, pattern) on a field sent as a file are no longer validated.
  • An after_request_body_property_validation hook sees the empty placeholder for such a field.
  • Parts that are not files, and parts with a JSON contentType in the encoding map, are still read in full. Bounding those needs a size limit and is not part of this PR.

Measured through the middleware: a 300 MB upload grew RSS by 375 MB before, and by 63 MB after. A 900 MB upload also grows it by 63 MB, i.e. memory no longer scales with the upload — the rest is Rack's own buffering.

🤖 Generated with Claude Code

@ahx
ahx marked this pull request as ready for review August 12, 2026 10:24
@ahx
ahx force-pushed the dont-load-binary-file-uploads branch 4 times, most recently from cdd08ac to e4dac66 Compare August 12, 2026 13:12
Multipart parts that are sent as a file were read into memory in full
before the request body was validated, so a single large upload to any
documented multipart/form-data route could exhaust the memory of the
server process. Request validation runs before the application, so this
did not require authentication.

Such a part is now passed through as Rack parsed it, and validated as an
empty binary String, because the content of a file is accepted as is.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ahx
ahx force-pushed the dont-load-binary-file-uploads branch from b4d7c52 to b31e094 Compare August 12, 2026 13:33
@ahx
ahx merged commit 3e17e01 into main Aug 12, 2026
1 of 31 checks passed
@ahx
ahx deleted the dont-load-binary-file-uploads branch August 12, 2026 13:33
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.

1 participant