Repository navigation
Stop editorial metadata leaking to unauthorised REST readers - #1036
Merged
GaryJones merged 1 commit intoAug 18, 2026
Merged
Conversation
GaryJones
force-pushed
the
GaryJones/rest-editorial-metadata-read-exposure
branch
2 times, most recently
from
August 18, 2026 10:57
8a9445b to
0b6dedf
Compare
Registering the editorial metadata fields with show_in_rest lets Gutenberg
save them, but the flag also exposes their values on read to anyone who can
read the post. A published post is public, so every editorial metadata field
on every published post, including fields an editor marked as not viewable,
was served to anonymous clients over the REST API. The meta auth_callback
guards writes only and never applied to reads.
Add a rest_prepare_{post_type} filter that strips the editorial metadata keys
from responses for readers who cannot edit the post, mirroring the write-path
registration's supported post types. The capability check is per-post so the
collection endpoint, which returns many posts at once, is covered too. Editors
still receive the fields, so the block editor keeps working.
GaryJones
force-pushed
the
GaryJones/rest-editorial-metadata-read-exposure
branch
from
August 18, 2026 13:49
0b6dedf to
b5c9f83
Compare
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.
Summary
Since 0.10.0, the Editorial Metadata module registers its fields with
register_post_meta( … 'show_in_rest' => true … )so that Gutenberg can save them over the REST API. That flag is symmetric: it also exposes the values on read. Because a published post is readable by everyone, every editorial metadata field on every published post, including fields an editor explicitly marked as not viewable, was served to anonymous, unauthenticated clients. The collection endpoint (/wp/v2/posts) returned them in bulk, so an attacker did not even need to know a post ID.The
auth_callbacksupplied with the registration is correct, but it governs writes only. Core exposesshow_in_restmeta on read to anyone who can read the object, and there is no per-field read gate in core meta, so the write-side callback never applied here. This is CWE-200 information disclosure; the impact is contextual and depends on what a newsroom stores in those fields (source identities, contact details, legal notes).The fix keeps
show_in_restintact, so saving from the block editor is unaffected, and adds arest_prepare_{post_type}filter that strips the editorial metadata keys from responses for readers who cannot edit the post. The capability check is per-post so the collection endpoint is covered too, and it mirrors the existing pattern already used by the Custom Status module (register_rest_api_filters+rest_prepare_{post_type}). Editors continue to receive the fields, so the editor keeps working.An integration test asserts both halves of the contract: an anonymous read must not contain the keys, and an editor's read must still return the stored value.
The version bump, CHANGELOG entry and POT regeneration are intentionally left out of this PR; they will be handled on the separate release branch.
Test plan
composer test:integration -- --filter EditorialMetadataTestpasses, includingtest_rest_read_hides_editorial_metadata_from_unauthorised_usersGET /wp-json/wp/v2/posts/<id>on a published post with editorial metadata no longer returns the_ef_editorial_meta_*keys