Skip to content

REST API: Verify sideloaded file names before finalize stores them. - #13012

Open
adamsilverstein wants to merge 2 commits into
WordPress:trunkfrom
adamsilverstein:fix/finalize
Open

REST API: Verify sideloaded file names before finalize stores them.#13012
adamsilverstein wants to merge 2 commits into
WordPress:trunkfrom
adamsilverstein:fix/finalize

Conversation

@adamsilverstein

Copy link
Copy Markdown
Member

REST API: Bind finalize sub-size file names to their sideload.

Fix an issue where the finalize endpoint stored the sub-size file names a client sent without confirming a sideloaded image had produced them for that attachment. Those names are later resolved against the attachment's upload directory and read or deleted, so finalize could record a file the upload never created. To address this, the sideload endpoint now records each name it generates under a _wp_sideloaded_file post meta key, and the finalize endpoint accepts a name only when:

  1. a prior sideload recorded it in post meta,
  2. it is the attachment's own attached file, or
  3. it is already stored in the attachment's metadata.

Anything else returns a rest_invalid_sub_size_file error (HTTP 400) before any metadata is written. Sideloads are also pinned to the attachment's own subdirectory via the upload_dir filter, so names are in the directory they later resolve against. Finalize stays safe to repeat: a name already in the attachment's metadata is accepted again.

Follow-up to r61982, r62609.

The finalize endpoint wrote the client-supplied `file` and `original_image`
values straight into the attachment metadata, where they are later resolved
inside the attachment's upload directory and read or deleted. A request could
point one attachment's metadata at another attachment's files. Sideload also
derived its upload directory from the parent post's date, so a file could land
in a directory the names it produced never resolve against.

Record every file name the sideload endpoint produces as a provenance row on
the attachment, and accept a finalize submission only when each name matches
one of those rows, the attachment's own attached file, or a name already stored
in its metadata. Consumed rows are dropped once their names are recoverable
from the metadata, so a retried finalize still validates. Pin sideload uploads
to the attachment's own uploads subdirectory, and reject an attachment stored
outside the uploads directory rather than guessing a location for it.

Tighten the surrounding validation while the names are in hand: apply the
declared schema before the custom callbacks that would otherwise replace it,
require non-empty size names and bound the number of entries, share the
size-name check between both endpoints, and reject a grouped entry naming a
special size, which each of the finalize branches stores on its own. Sideload
now checks dimensions against every name a shared file is registered under and
deletes the uploaded file on the error paths that previously left it behind.

The qunit fixture is regenerated for the schema additions.
@github-actions

Copy link
Copy Markdown

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

@adamsilverstein

Copy link
Copy Markdown
Member Author

Fixing the failing tests which aren't setting up their data correctly since this change.

@adamsilverstein adamsilverstein self-assigned this Aug 12, 2026
The finalize endpoint now stores a sub-size file name only when a prior
sideload for that attachment produced it, and an array of image sizes is
validated against every size the shared file is registered under. Tests
that hand-built a sub_sizes payload, or that grouped a special size or an
oversized file into an array, exercised states the endpoints no longer
accept and failed against the hardened controller.

Sideload the sub-sizes the finalize tests submit so the payload carries
names the endpoint produced, size the shared file for the smallest size in
its group, and assert that a special size sent as an array is rejected.
@adamsilverstein
adamsilverstein marked this pull request as ready for review August 12, 2026 05:27
@github-actions

Copy link
Copy Markdown

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.

Core Committers: Use this line as a base for the props when committing in SVN:

Props adamsilverstein.

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant