Skip to content

Prevent flagging of hidden comments such as order notes - #25

Merged
GaryJones merged 1 commit into
developfrom
GaryJones/pr-validation-fix
Aug 19, 2026
Merged

GaryJones merged 1 commit into
developfrom
GaryJones/pr-validation-fix

Conversation

@GaryJones

Copy link
Copy Markdown
Contributor

Summary

Safe Report Comments lets visitors flag a comment as inappropriate, and once a configurable number of reports is reached the comment is moved to moderation. The public AJAX handler behind this, flag_comment(), validated only that the submitted comment_id was numeric and that the request carried the plugin's report nonce. That nonce is a single global value, shared by every anonymous visitor and not tied to any particular comment, so it proves only that the caller loaded a page with a report link, not that the target was ever meant to be reportable.

WordPress stores more than blog comments in the comments table. WooCommerce, for instance, keeps internal order notes there with a comment_type of order_note. Because nothing checked the target's type, an anonymous visitor could lift the global nonce from any public post and submit reports against arbitrary comment IDs, including hidden records that never had a report link rendered. On reaching the threshold the plugin called wp_set_comment_status( $comment_id, 'hold' ) on them, changing their approval state and firing the moderation hooks, with no authorisation for that specific target. This was raised in an external security report, with WooCommerce order notes as the demonstrated case.

The fix adds an is_reportable_comment() guard that flag_comment() now consults before any report metadata is written or status changed. It confirms the comment exists and is an ordinary public comment type (an empty type or comment), rejecting order notes, pingbacks, trackbacks and other subtypes that merely share the table. Two filters keep it extensible: safe_report_comments_reportable_comment_types to adjust the accepted types and safe_report_comments_is_reportable_comment to veto or allow a specific target. Rejected requests reuse the existing invalid-values response, so client behaviour for a bad request is unchanged. Extracting the check into its own method also makes it directly testable, and the new tests/test-reportable-comment.php locks in the behaviour for ordinary comments, order notes, pingbacks, trackbacks, a missing comment and both filters.

The change is deliberately narrow: it gates the target by type only. Verifying parent-post visibility (comments on private or password-protected posts) was noted in the report as a lesser, separate concern, and the safe_report_comments_is_reportable_comment filter is the intended extension point should we choose to add it. One claim in the report, that a held order note vanishes from wc_get_order_notes(), looked doubtful because WP_Comment_Query returns both approved and held comments by default; this PR closes the underlying authorisation gap regardless, since acting on a non-reportable target is wrong on its own.

Test plan

  • CI runs the new integration test on PHP 7.4 and 8.3 against WordPress latest, single and multisite.
  • Manual: with flagging enabled and WooCommerce active, reporting an order_note comment ID via admin-ajax.php returns the invalid-values message and leaves the note untouched, while an ordinary comment still reaches moderation at the threshold.

The public flag_comment AJAX handler checked only that comment_id was
numeric and carried the global report nonce. That nonce is shared by
every anonymous visitor and is not bound to a comment, so any numeric ID
could be reported, including records that merely share the comments
table such as WooCommerce order notes. Once the threshold was reached
these hidden entries were moved to moderation even though no report link
was ever rendered for them.

Gate flagging on a new is_reportable_comment() helper so only existing,
ordinary comment types are actionable, and expose filters to adjust the
reportable types or veto a target. Add a regression test covering order
notes, pingbacks, trackbacks, missing comments and the filters.
@GaryJones
GaryJones force-pushed the GaryJones/pr-validation-fix branch from 859ad36 to f4449ec Compare August 19, 2026 00:17
@GaryJones
GaryJones merged commit 7f9fb23 into develop Aug 19, 2026
6 checks passed
@GaryJones
GaryJones deleted the GaryJones/pr-validation-fix branch August 19, 2026 09:14
@GaryJones GaryJones added this to the Next milestone Aug 19, 2026
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