Skip to content

fix: escape user-controlled values rendered as raw backend HTML (stored XSS)#6581

Merged
gharlan merged 2 commits into
5.xfrom
claude/eager-hopper-o37g5b
Jun 29, 2026
Merged

fix: escape user-controlled values rendered as raw backend HTML (stored XSS)#6581
gharlan merged 2 commits into
5.xfrom
claude/eager-hopper-o37g5b

Conversation

@gharlan

@gharlan gharlan commented Jun 29, 2026

Copy link
Copy Markdown
Member

Several places concatenated database/filesystem values into backend HTML without rex_escape(), leading to stored XSS. Most of these flows are invisible to the Psalm taint analysis because they cross dynamic-dispatch boundaries (extension-point handlers invoked via call_user_func, a fragment var set with escaping disabled, and a rex_list 'custom' column formatter which is not auto-escaped), so the static taint graph is severed between source and sink.

Fixed sinks:

  • media_manager: the MEDIA_IS_IN_USE handler rendered the effect type name unescaped.
  • mediapool: the MEDIA_IS_IN_USE warning rendered the referencing article name unescaped.
  • metainfo: the MEDIA_IS_IN_USE handler rendered article, category, media filename and clang names unescaped.
  • mediapool sync page: on-disk filenames were rendered unescaped in the writable/not-writable lists.
  • media_manager effects list: the 'custom' column formatter returned the raw effect short name from the DB when the effect class is no longer registered.
  • phpmailer checkmail page: the SMTP server debug output and ErrorInfo were rendered unescaped (rex_escape applied before nl2br so line breaks are preserved).

All affected values are now passed through rex_escape() before being embedded into HTML.

…ed XSS)

Several places concatenated database/filesystem values into backend HTML
without rex_escape(), leading to stored XSS. Most of these flows are
invisible to the Psalm taint analysis because they cross dynamic-dispatch
boundaries (extension-point handlers invoked via call_user_func, a fragment
var set with escaping disabled, and a rex_list 'custom' column formatter
which is not auto-escaped), so the static taint graph is severed between
source and sink.

Fixed sinks:

- media_manager: the MEDIA_IS_IN_USE handler rendered the effect type name
  unescaped (GHSA-mf2p-wjp4-99pq).
- mediapool: the MEDIA_IS_IN_USE warning rendered the referencing article
  name unescaped.
- metainfo: the MEDIA_IS_IN_USE handler rendered article, category, media
  filename and clang names unescaped.
- mediapool sync page: on-disk filenames were rendered unescaped in the
  writable/not-writable lists (GHSA-w998-qmw9-mf4m).
- media_manager effects list: the 'custom' column formatter returned the
  raw effect short name from the DB when the effect class is no longer
  registered.
- phpmailer checkmail page: the SMTP server debug output and ErrorInfo were
  rendered unescaped (rex_escape applied before nl2br so line breaks are
  preserved).

All affected values are now passed through rex_escape() before being
embedded into HTML.
@gharlan gharlan added this to the REDAXO 5.21.2 milestone Jun 29, 2026
@rex-bot rex-bot added the bug label Jun 29, 2026
@gharlan gharlan merged commit 2daaa3a into 5.x Jun 29, 2026
18 checks passed
@gharlan gharlan deleted the claude/eager-hopper-o37g5b branch June 29, 2026 08:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

2 participants