fix(api): cap resize amplification and correct the error contract - #37
Merged
Merged
Conversation
|
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.
Why
The only cap on `/compress` output was 100 megapixels absolute, with no relation to the input. A 1x1 PNG of about 70 bytes with `maintainAspect=false&resizeWidth=10000&resizeHeight=10000` forced a ~400 MB RGBA allocation, a full Catmull-Rom rescale, and a max-compression PNG encode. The request costs the attacker nothing and holds a throttle slot for the whole encode.
Four smaller contract gaps compounded it:
What changed
The documented limits (`MaxFileSize`, `MaxPixels`, `MaxDimension`) are unchanged; the web client mirrors them.
Tests
Seven new tests: per-side and upscale-factor rejection plus a passing 4x upscale, cancellation timed to land after the encode (via a context that only reports done from its 4th `Err()` call), malformed-multipart 400, and GIF rejection using hand-built GIF bytes. The GIF test avoids importing `image/gif`, since that package's `init()` would re-register the decoder and make the test pass for the wrong reason.
Verification
`go test ./...` and `go vet ./...` pass in both Go modules; `bun run test` passes at the repo root (web 43, api, core).