Make WordPress Core

Opened 5 months ago

Closed 6 weeks ago

Last modified 4 weeks ago

#64798 closed enhancement (fixed)

REST API: Add dimension validation to sideload endpoint

Reported by: adamsilverstein Owned by: adamsilverstein
Priority: normal Milestone: 7.1
Component: REST API Version:
Severity: normal Keywords: has-patch has-unit-tests commit
Cc: Focuses:

Description (last modified by adamsilverstein)

Summary

Backport for https://github.com/WordPress/wordpress-develop/pull/11100

Add image dimension validation to the wp/v2/media/<id>/sideload REST API endpoint to prevent uploading images with dimensions that don't match the target image size constraints.

Description

The REST API sideload endpoint (wp/v2/media/<id>/sideload) currently accepts uploaded images without validating that their dimensions are appropriate for the specified image_size. This means a client could sideload a 640x480 image as a thumbnail (which is registered as 150x150), producing incorrect metadata and potentially broken layouts.

This ticket adds a validate_image_dimensions() method to WP_REST_Attachments_Controller that validates uploaded image dimensions before processing, with size-specific rules:

Validation rules

  • original size: Uploaded dimensions must match the original attachment dimensions exactly.
  • full and scaled sizes: Only requires positive dimensions (no upper bound constraint).
  • Regular registered sizes (e.g. thumbnail, medium, large): Dimensions must not exceed the registered size maximums, with a 1px tolerance for rounding differences.
  • Unknown sizes: Returns an error for unregistered image size names.

Implementation details

  • Adds private method validate_image_dimensions( int $width, int $height, string $image_size, int $attachment_id ) to WP_REST_Attachments_Controller.
  • Moves the wp_getimagesize() call earlier in sideload_item() so dimensions are available for validation before metadata handling.
  • On validation failure, cleans up the uploaded file with wp_delete_file() before returning the error.
  • Uses wp_get_registered_image_subsizes() to look up size constraints for registered sizes.

Error codes

  • rest_upload_invalid_dimensions — Image has zero or negative dimensions.
  • rest_upload_dimension_mismatch — Dimensions don't match expected constraints for the target size.
  • rest_upload_unknown_size — The specified image_size is not registered.

All errors return HTTP 400 status.

Change History (12)

#1 @adamsilverstein
5 months ago

  • Description modified (diff)

This ticket was mentioned in PR #11100 on WordPress/wordpress-develop by @adamsilverstein.


5 months ago
#2

  • Keywords has-patch added

## Summary

Builds on #11015. Adds dimension validation to the sideload endpoint.

  • Adds validate_image_dimensions() private method to WP_REST_Attachments_Controller
  • Validates uploaded image dimensions against expected size constraints in the wp/v2/media/<id>/sideload endpoint
  • Moves wp_getimagesize() call earlier in sideload_item() to validate before metadata handling

### 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)

## Test plan

  • [x] test_sideload_item_rejects_oversized_dimensions — uploads 640x480 image as thumbnail (150x150), expects 400 with rest_upload_dimension_mismatch
  • [x] test_sideload_item_accepts_valid_dimensions — uploads 50x50 image as thumbnail, expects 200

Corresponding Gutenberg PR: https://github.com/WordPress/gutenberg/pull/74903

This ticket was mentioned in Slack in #core by audrasjb. View the logs.


5 months ago

#4 @joedolson
5 months ago

  • Milestone 7.07.1

#5 @audrasjb
5 months ago

  • Version trunk

As per today's pre-RC1 scrub, let's move this ticket to 7.1

@adamsilverstein commented on PR #11100:


3 months ago
#6

Pushed c57a9752cc addressing @apermo's two suggestions (in_array() + dimension_exceeds_max() helper).

Re-merging trunk: skipped intentionally for now. Trunk currently has the entire client-side media feature removed (commit c863860ccf, "Media: Remove client-side media processing feature for now."), including the sideload endpoint this PR validates against. The feature is being re-introduced in #11324, which is still open. Merging trunk here today would just delete the endpoint this PR builds on, so it's better to wait for #11324 to land and then rebase. CI on this branch will look red until then for the same reason.

#7 @adamsilverstein
3 months ago

  • Keywords has-unit-tests commit added
  • Type defect (bug)enhancement

@westonruter commented on PR #11100:


3 months ago
#8

I fixed some PHPStan errors in 5634d1d. The remaining issues are addressed by the types added in https://github.com/WordPress/wordpress-develop/pull/12003.

@westonruter commented on PR #11100:


3 months ago
#9

The changes look good, but there aren't tests added. Are these still coming?

@adamsilverstein commented on PR #11100:


6 weeks ago
#10

The changes look good, but there aren't tests added. Are these still coming?

Added.

#11 @adamsilverstein
6 weeks ago

  • Owner set to adamsilverstein
  • Resolutionfixed
  • Status newclosed

In 62619:

REST API: Add dimension validation to sideload endpoint.

Validate uploaded image dimensions in the wp/v2/media/<id>/sideload endpoint before metadata is written, ensuring sideloaded files match the requested image_size. A new private validate_image_dimensions() helper on WP_REST_Attachments_Controller enforces:

  • The original size must match the original attachment dimensions exactly.
  • The full and scaled sizes require positive dimensions only.
  • Regular registered sizes must not exceed the registered sub-size maximums, with a 1px tolerance for rounding differences.

Follow-up to [62428].

Props apermo, westonruter.
Fixes #64798.

This ticket was mentioned in PR #12550 on WordPress/wordpress-develop by @adamsilverstein.


4 weeks ago
#12

Backport of https://github.com/WordPress/gutenberg/pull/80295 (part of https://github.com/WordPress/gutenberg/issues/77582).

## Problem

In the client-side media upload flow, the client uploads the original file unmodified, applies the EXIF rotation itself, and sideloads the rotated file with image_size=original. For quarter-turn orientations (EXIF 5-8) the rotated file's width and height are swapped relative to the stored metadata, so validate_image_dimensions() rejected the sideload with a 400 (rest_upload_dimension_mismatch) and the upload failed.

The original sideload also stored the rotated file as original_image while the un-rotated upload stayed the attachment's main file, which is backwards relative to what core does when it rotates on upload.

## Solution

  • Treat an image_size=original sideload like a scaled sideload: the supplied (rotated) file replaces the attachment's main file, and the untouched upload is kept as original_image. This mirrors the swap _wp_image_meta_replace_original() performs in wp_create_image_subsizes().
  • Accept transposed dimensions when validating an original sideload.
  • Reset the stored EXIF orientation to 1 in finalize for both original and scaled sub-sizes, as wp_create_image_subsizes() does for its scale and rotate paths, so exif_orientation no longer reports the pre-rotation value once rotation has been applied.
  • Skip original/scaled finalize entries missing the file name so a malformed payload cannot blank out the main file metadata.

Includes a parity test asserting the client-side path produces the same attachment metadata (dimensions, orientation, original_image) as a classic server-side upload of the same EXIF-rotated fixture.

Note: See TracTickets for help on using tickets.