Repository navigation
Conversation
…ur Pinata POST /api/pinata-storage/image/put had no authentication: anyone could pin arbitrary files to the project's Pinata account. Its sibling /api/pinata-storage/put was closed in 09a042a; this one was missed. It also streamed every request, of any size up to formidable's 200 MB default, to an OS temp file that was never deleted, and only then checked the 1 MB limit. Now: rate limit, then wallet session or v1 bearer (same rule as put.ts), then multipart-only with a required Content-Length of at most 1 MB + 64 KB, parsed in memory with formidable's caps. Exactly one file part named `file`, of an image type. Nothing touches disk. The unused vercel-storage image route answers 501 before reading the body instead of after writing it to disk. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SoVc5PAx9wDUyD35Km5417
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
POST /api/pinata-storage/image/put(the DRep / wallet avatar upload used byImgDragAndDrop) had no authentication. Anyone on the internet could pin arbitrary files to the project's Pinata account, burning its quota, and nothing recorded who did it. Its sibling/api/pinata-storage/putwas closed in 09a042a. This one was missed.It also had an unauthenticated disk-filling bug. formidable streamed every request to an OS temp file before the handler looked at it:
/api/vercel-storage/image/puthad the same disk problem. It has no callers and answered 501 only after parsing.Changes
pinata-storage/image/put.tschecks, in this order:Rate limit: 20/min per IP.
Auth: a wallet session or a v1 bearer token. This is the same rule as
put.ts, and it runs before a byte of the body is read.Content type must be
multipart/form-data, else 415.Content-Lengthis required (411) and must be at most 1 MB + 64 KB (413). Node stops reading at the declared length, so this is what bounds the body. A chunked request would otherwise go around formidable's caps, which count part bodies but not part headers. The reviewer measured a 200 MB part header taking about 362 MB of RSS.Parsing happens in memory (
fileWriteStreamHandler) with formidable's caps:maxFiles: 1, and the file must be in thefilefield;maxFileSizeandmaxTotalFileSizeare 1 MB.Nothing is written to disk.
The upload must declare an
image/*type, which is what the dropzone accepts. The type comes from the client, so this blocks casual misuse such as pinning HTML. It does not stop a determined caller.vercel-storage/image/put.tsnow answers 501 without reading the body.The response contract for the in-app caller is unchanged:
{ url, cid, id }.Tests
src/__tests__/pinataImageUpload.test.tshas 24 tests. They use real formidable and real multipart bodies, and only auth, the rate limiter andfetchare mocked. They cover:bodyParser: falseconfig export is present;7 of these fail against the old handlers.
Other checks:
npx tsc --noEmit: clean.node scripts/run-tests.mjs: 151 suites / 1680 tests passed (2 skipped), plus the ESM project 11 / 97.next build --webpack: OK. Bundle budget: within budget, since only server routes changed.Through a real
next start, with a session cookie and a dummy Pinata JWT:text/htmlA separate review agent read the diff cold twice. The first pass caught a dropped
bodyParser: falseexport, which would have hung every upload. It also caught the non-multipart plugin bypass and the chunked part-header growth. All three are fixed above.Not verified / for the maintainer
ImgDragAndDropshows only "Failed to upload image." and discards the server's "connect and authorize a wallet" message. Surfacing that message would be a small follow-up./api/pinata-storage/image/existsand the/api/blockfrost/*proxy are still unauthenticated with no rate limit. Neither is touched here.Generated by Claude Code