Cursor prompt to build a file upload endpoint
File uploads are where naive handlers get burned: memory-buffered bodies, spoofed extensions, path traversal hiding in filenames. This prompt directs Cursor to stream uploads with an early size abort, validate magic bytes, randomize storage keys, and persist metadata, finishing with a test that tries to sneak an executable through disguised as a png.
Last updated
Build a file upload endpoint in this codebase in {{language}}. Accept multipart/form-data on POST /uploads, stream the file to disk or S3-compatible storage rather than buffering it in memory, and enforce a 10 MB size cap that aborts the stream early instead of reading the whole body first. Validate file type by magic bytes, not extension or client Content-Type, allowing only png, jpeg, and pdf. Generate a random storage key, never trust the original filename, and strip path separators before persisting metadata (original name, mime type, size, storage key) to {{database}}. Return 201 with the file id and an expiring download URL, 413 for oversize, and 415 for disallowed types. Add tests uploading a valid image, an oversized file, and an exe renamed to .png, then run them and report results.Customize it
Runs in your browser. Nothing you type here is sent anywhere.
Build a file upload endpoint in this codebase in TypeScript. Accept multipart/form-data on POST /uploads, stream the file to disk or S3-compatible storage rather than buffering it in memory, and enforce a 10 MB size cap that aborts the stream early instead of reading the whole body first. Validate file type by magic bytes, not extension or client Content-Type, allowing only png, jpeg, and pdf. Generate a random storage key, never trust the original filename, and strip path separators before persisting metadata (original name, mime type, size, storage key) to PostgreSQL. Return 201 with the file id and an expiring download URL, 413 for oversize, and 415 for disallowed types. Add tests uploading a valid image, an oversized file, and an exe renamed to .png, then run them and report results.
Same task in other tools
Questions about this prompt
Can I switch storage from local disk to S3 without rewriting the prompt?
Add "store files in S3 with the bucket name from an env var, using streaming or presigned uploads" and keep everything else. The validation, size cap, and metadata rules are storage-agnostic, and Cursor will swap the storage layer while preserving them.
Why validate magic bytes when the Content-Type header exists?
The client sets Content-Type, and an attacker sets it to whatever passes. Magic bytes are read from the actual file stream, so a renamed executable fails even with image/png declared. The final test in the prompt exists specifically to prove this check works.
The size cap works but the server still reads the entire body first. How do I fix that?
That means the agent used a buffered parser. Tell Cursor to switch to the streaming API of your framework's multipart library and abort the request once the byte counter passes the limit, then re-run the oversized upload test and watch memory stay flat.