Make WordPress Core

Opened 10 hours ago

Last modified 10 hours ago

#66695 new defect (bug)

REST API: Validate note reaction keys instead of stripping tags

Reported by: adamsilverstein Owned by:
Priority: normal Milestone: Awaiting Review
Component: Notes Version: trunk
Severity: normal Keywords: has-patch has-unit-tests
Cc: Focuses: rest-api

Description

Claude drafted this ticket from the Gutenberg fix:

Follow up to [64488].

A note reaction stores its emoji as a hex key in comment_content (eg. 2764 for a heart). WP_REST_Comments_Controller validates that key against the curated set on create, but each time it reads one back it runs the content through wp_strip_all_tags() and uses whatever comes out. There are five calls in class-wp-rest-comments-controller.php.

This has two problems:

  • The reaction summary trusts any row. A reaction written by something other than the controller, with heart or 1F680 as its content, shows up in reaction_summary as another emoji.
  • Stripping folds different content together. A <b>2764</b> row lands on the same key as a real 2764 row and one count overwrites the other.

Proposed fix

  • Add a check for the shape of a key: lowercase hex code points joined by -, each a Unicode scalar value (nothing past U+10FFFF, no surrogates). The summary skips rows that fail it.
  • Compare stored content to the validated key exactly in the duplicate check and the concurrent-request cleanup.
  • On create, trim the content and require an exact match with a curated key. <b>2764</b> was accepted and stored as 2764 before; it would now return rest_comment_invalid_reaction.

The same change for the Gutenberg plugin, with tests: ​https://github.com/WordPress/gutenberg/pull/86775

Raised by @dmsnell in review: ​https://github.com/WordPress/gutenberg/pull/83169#discussion_r4547481345

Change History (1)

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


10 hours ago
#1

  • Keywords has-patch has-unit-tests added

_Claude Code ported the Gutenberg fix over and wrote this up:_

Stop reading note reaction keys through wp_strip_all_tags() in WP_REST_Comments_Controller. A stored reaction now counts only when its content has the shape of a reaction key, and validated keys are compared exactly.

A reaction stores its emoji as a hex key in comment_content (eg. 2764 for a heart). The controller validates that key against the curated set on create, but each of the five places it read one back ran the content through wp_strip_all_tags() and used whatever came out. So a reaction row written by something other than the controller, with heart or 1F680 as its content, showed up in reaction_summary as another emoji. And a <b>2764</b> row landed on the same key as a real 2764 row, with one count overwriting the other.

  • Add a private is_reaction_key() that checks the shape: lowercase hex code points joined by -, each a Unicode scalar value (nothing past U+10FFFF, no surrogates). The summary skips rows that fail it. The check is on the shape and not the curated set, so reactions stay readable if the set changes.
  • The duplicate check and the concurrent-request cleanup compare the stored content to the validated key directly.
  • On create the content is trimmed and has to match a curated key exactly.

One behavior change to look at: test_create_reaction_stores_canonical_key from [64488] expected <b>2764</b> to be accepted and stored as 2764. That request now returns rest_comment_invalid_reaction, and the test is renamed to test_create_reaction_rejects_markup_around_key. The editor only ever sends the bare key. If accepting markup on create was deliberate, that one line can go back to stripping without affecting the rest.

Testing: vendor/bin/phpunit --filter WP_Test_REST_Comments_Controller. The new test_reaction_summary_omits_malformed_reaction_content covers six kinds of malformed content; five of those cases and the markup test fail on trunk.

Gutenberg PR: ​https://github.com/WordPress/gutenberg/pull/86775
Raised by @dmsnell in ​https://github.com/WordPress/gutenberg/pull/83169#discussion_r4547481345

Use of AI Tools

Claude Code wrote the code, the tests and this description, porting the change from the Gutenberg PR. I will review and test.

Note: See TracTickets for help on using tickets.