Skip to content

Add dimension validation to sideload endpoint#74903

Merged
adamsilverstein merged 6 commits into
trunkfrom
74360-ensure-rest-api-complete
May 15, 2026
Merged

Add dimension validation to sideload endpoint#74903
adamsilverstein merged 6 commits into
trunkfrom
74360-ensure-rest-api-complete

Conversation

@adamsilverstein
Copy link
Copy Markdown
Member

@adamsilverstein adamsilverstein commented Jan 23, 2026

Summary

Adds validation to ensure uploaded image dimensions match expected dimensions for the specified image size in the wp/v2/media/<id>/sideload endpoint.

Fixes #74360

Problem

Previously, the sideload endpoint accepted any image regardless of its dimensions. A user could upload a 1000x1000 image claiming it's a "thumbnail" (150x150), and the code would accept it without validation.

Solution

Added a validate_image_dimensions() method that checks uploaded dimensions against expected size constraints:

  • 'original' size: Must match original attachment dimensions exactly
  • 'full' size (PDF thumbnails): Requires positive dimensions only
  • Regular sizes: Dimensions must not exceed registered size maximums (with 1px tolerance for rounding differences)

The validation runs after the file is uploaded but before metadata is updated. If validation fails, the uploaded file is cleaned up and a WP_Error is returned.

Test plan

  • Run existing tests to ensure no regressions
  • Verify oversized images are rejected with 400 error
  • Verify correctly-sized images are accepted with 200 response
npm run test:unit:php -- --filter=Gutenberg_REST_Attachments_Controller_Test

🤖 Generated with Claude Code

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jan 23, 2026

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: adamsilverstein <[email protected]>
Co-authored-by: swissspidy <[email protected]>
Co-authored-by: ramonjd <[email protected]>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@adamsilverstein adamsilverstein added [Type] Enhancement A suggestion for improvement. [Feature] Client Side Media Media processing in the browser with WASM labels Jan 23, 2026
@github-project-automation github-project-automation Bot moved this to 🔎 Needs Review in WordPress 7.0 Editor Tasks Jan 23, 2026
@adamsilverstein adamsilverstein requested review from andrewserong, ramonjd and swissspidy and removed request for spacedmonkey January 23, 2026 17:22
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jan 23, 2026

Flaky tests detected in 8b8aa9a.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/24863531627
📝 Reported issues:

@adamsilverstein adamsilverstein linked an issue Jan 23, 2026 that may be closed by this pull request
4 tasks
@adamsilverstein adamsilverstein force-pushed the feature/client-side-media-dev branch from 1fb78d7 to 89e2a02 Compare February 2, 2026 20:04
@adamsilverstein adamsilverstein marked this pull request as draft March 1, 2026 06:17
Validates uploaded image dimensions against expected size constraints
in the wp/v2/media/<id>/sideload endpoint. This prevents users from
uploading incorrectly-sized images for a specified image size.

Validation rules:
- 'original' size: must match original attachment dimensions exactly
- 'full' and 'scaled' sizes: requires positive dimensions only
- Regular sizes: dimensions must not exceed registered size maximums
  (with 1px tolerance for rounding differences)

Also updates existing tests to use appropriately-sized images and adds
two new test cases for dimension validation.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@adamsilverstein adamsilverstein changed the base branch from feature/client-side-media-dev to trunk March 1, 2026 07:17
@adamsilverstein adamsilverstein force-pushed the 74360-ensure-rest-api-complete branch from a537683 to beff757 Compare March 1, 2026 09:22
Copy link
Copy Markdown
Member

@swissspidy swissspidy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense!

adamsilverstein and others added 2 commits March 1, 2026 17:48
Links Gutenberg PR #74903 (dimension validation for sideload endpoint)
to its corresponding WordPress Core PR.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Remove the file_exists check from filter_wp_unique_filename
so sideloaded sub-sizes can replace existing files. The
attachment name check is sufficient to prevent unintended
overwrites. Also consolidate the positive-dimension check
and fix translators comment argument order.
@adamsilverstein adamsilverstein marked this pull request as ready for review March 17, 2026 21:46
@adamsilverstein adamsilverstein added the [Status] In Progress Tracking issues with work in progress label Mar 17, 2026
@adamsilverstein adamsilverstein self-assigned this Mar 17, 2026
@adamsilverstein
Copy link
Copy Markdown
Member Author

@andrewserong another one to review when you have a chance, no hurry though!

Comment thread lib/media/class-gutenberg-rest-attachments-controller.php
Copy link
Copy Markdown
Member

@ramonjd ramonjd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Just left some non blocking questions. This is still an experiment, right?

I uploaded a large image and told the sideload endpoint it was a thumbnail:

curl -u "admin:Ysn5 AMiG 6N2k cEAK guz8 KqoZ" \
  -X POST "http://localhost:8888/wp-json/wp/v2/media/243/sideload?image_size=thumbnail" \
  -H "Content-Disposition: attachment; filename=196-150x150.jpg" \
  -H "Content-Type: image/jpeg" \
  --data-binary @./196.jpg

->>>

{"code":"rest_upload_dimension_mismatch","message":"Uploaded image width (3008) exceeds maximum for \"thumbnail\" size (150).","data":{"status":400}}%

On trunk the response was 200.

Also tested happy path:

curl -u "admin:Ysn5 AMiG 6N2k cEAK guz8 KqoZ" \
  -X POST "http://localhost:8888/wp-json/wp/v2/media/244/sideload?image_size=thumbnail" \
  -H "Content-Disposition: attachment; filename=test-image-1-100x100.jpg-150x150.jpg" \
  -H "Content-Type: image/jpeg" \
  --data-binary @./test-image-1-100x100.jpg

Comment thread lib/media/class-gutenberg-rest-attachments-controller.php
Comment thread lib/media/class-gutenberg-rest-attachments-controller.php
Comment thread lib/media/class-gutenberg-rest-attachments-controller.php
Address review feedback: return a WP_Error when wp_getimagesize()
returns false (corrupted file, unsupported format) instead of silently
proceeding with zero dimensions. This also simplifies the downstream
code since $size is now guaranteed to be a valid array.
@adamsilverstein
Copy link
Copy Markdown
Member Author

I uploaded a large image and told the sideload endpoint it was a thumbnail

"thumbnail" here might just mean "sub size", let me test with a large image to see if I get the expected -scaled image.

Layer dimension validation on top of trunk's sub_size_data return
pattern: read dimensions once up front, run validate_image_dimensions
(now accepting string|array image_size), then build the flat sub-size
payload the finalize endpoint expects. Keep PR and trunk test
coverage side by side.
Two tests had stale assertions after the switch to 'thumbnail'
size (still expecting 'medium'), and two newer trunk tests used
canola.jpg (640x480) in their sideload body, which now fails
dimension validation against medium (300x300) and thumbnail
(150x150). Use test-image.jpg (50x50) to fit within constraints.
@adamsilverstein
Copy link
Copy Markdown
Member Author

adamsilverstein commented May 6, 2026

testing with a large image, I do see a scaled image created. I noticed a separate bug though, where the subsizes all get the "-scaled" naming suffix that is supposed to apply only to the scaled image itself. I am opening a separate issue for this.

current:
scaled names wrong

correct (server):
correct file naming

@adamsilverstein
Copy link
Copy Markdown
Member Author

adamsilverstein commented May 6, 2026

testing with a large image, I do see a scaled image created. I noticed a separate bug though, where the subsizes all get the "-scaled" naming suffix that is supposed to apply only to the scaled image itself. I am opening a separate issue for this.

opened #78037 which i want to land fist before testing and merging this.

@adamsilverstein adamsilverstein merged commit 9b4850e into trunk May 15, 2026
40 checks passed
@adamsilverstein adamsilverstein deleted the 74360-ensure-rest-api-complete branch May 15, 2026 16:11
@github-actions github-actions Bot added this to the Gutenberg 23.3 milestone May 15, 2026
adamsilverstein added a commit that referenced this pull request May 21, 2026
…ision

Reflect four client-side media PRs merged after these docs were last revised,
keeping the architecture and how-to guides in sync with current behavior:

- #76707: document the disabled libvips operation cache (Cache.max(0)) and the
  50-operation worker recycling that bound WASM linear-memory growth, plus the
  globalThis.__vipsDebug hook for capturing the suppressed vips output.
- #74903: document the sideload endpoint's image-dimension validation and its
  400 error responses (rest_upload_dimension_mismatch and friends).
- #78359: note that the finalize endpoint returns the refreshed attachment,
  which the editor uses to keep the block URL (and front-end srcset) in sync.
- #78038: clarify that sub-size filenames derive from the original basename and
  only the scaled full-size copy carries the -scaled suffix.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] Client Side Media Media processing in the browser with WASM [Status] In Progress Tracking issues with work in progress [Type] Enhancement A suggestion for improvement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ensure REST API endpoint for side-loaded media covers all requirements

3 participants