Skip to content

Fix stored XSS via unescaped Webmention-derived comment meta#613

Merged
pfefferle merged 1 commit into
mainfrom
fix/stored-xss-edit-comment-metabox
Jun 23, 2026
Merged

Fix stored XSS via unescaped Webmention-derived comment meta#613
pfefferle merged 1 commit into
mainfrom
fix/stored-xss-edit-comment-metabox

Conversation

@pfefferle

Copy link
Copy Markdown
Owner

Summary

Fixes a stored XSS reachable from unauthenticated Webmentions. Parser-derived author metadata (avatar, url) from a crafted source page was stored unsanitized and rendered unescaped into HTML value attributes in the comment edit metabox. When a moderator/administrator opens the comment, an attribute-breaking payload executes JavaScript in their privileged wp-admin session.

Source → sink:

  • includes/handler/class-mf2.php parses attacker-controlled u-photo / u-url (no validation)
  • includes/entity/class-item.php stores them as avatar / url comment meta
  • templates/edit-comment-form.php echoed them raw into value="..."

The meta was not sanitized on store either — register_meta() had no sanitize_callback.

Fix (defense in depth)

Sanitize on store — added register_meta() sanitize callbacks in class-receiver.php:

  • esc_url_raw for URL meta: avatar, url, webmention_source_url, webmention_target_url, webmention_vouch_url
  • sanitize_key for protocol, sanitize_text_field for webmention_last_modified
  • Left webmention_target_fragment / webmention_response_code / webmention_vouched untouched — they feed dedupe meta-queries/comparisons and are never rendered to HTML.

Escape on output — escaped every field in edit-comment-form.php plus other unescaped template sinks found while auditing:

  • templates/comment.phpcomment_author_url was echoed raw into an href and link text on a public page (a second XSS vector) → esc_url / esc_html
  • api-message.php, comments.php, comment-form.php, endpoint-form.php

Output escaping is needed independently because sanitize callbacks only apply to new writes; already-stored rows still need escaping on render.

Tests

  • New tests/phpunit/tests/class-test-admin-metabox.php covers storage sanitization and output escaping. Confirmed it fails against the unfixed code (emits a live <script> breakout) and passes with the fix.
  • Full suite: 73 tests, 117 assertions, all passing (via wp-env). Changed lines lint clean.

Version

Bumped to 5.8.1 (5.8.0 is already released) with changelog entries.

Parser-derived author metadata (avatar/url) from unauthenticated
Webmentions was stored unsanitized and rendered unescaped in the comment
edit metabox, allowing attribute-breaking payloads to execute JavaScript
in a moderator/admin wp-admin session.

Harden both layers:

* Sanitize comment meta on store via register_meta() sanitize callbacks
  (esc_url_raw for URL meta, sanitize_key/sanitize_text_field for the
  rest) so the database stays clean.
* Escape all output in edit-comment-form.php and the remaining template
  sinks (single-comment view, endpoint message/form, reaction heading),
  including the public comment.php where comment_author_url was echoed
  raw into an href and link text.

Add regression tests covering both storage sanitization and output
escaping. Bump version to 5.8.1.
@pfefferle pfefferle merged commit f30cd4c into main Jun 23, 2026
8 checks passed
@pfefferle pfefferle deleted the fix/stored-xss-edit-comment-metabox branch June 23, 2026 10:14
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