Skip to content

Image block: $/\ in img alt or src corrupted in lightbox markup (preg_replace backreference) #79368

Closed

Description

@lonesahilnazir

Description

Description

block_core_image_render_lightbox() injects the lightbox trigger button by
calling:

$body_content = preg_replace( '/<img[^>]+>/', $button, $body_content );

where $button begins with the matched <img> tag ($img[0]), which embeds
author/user-controlled attribute values (src, alt, title, class).

In a preg_replace() replacement string, the sequences $0, $1, ${1},
\0, \1, … are interpreted as backreferences. So when an image's alt text
or filename contains such a sequence, it is silently rewritten — a reference
to a non-existent capture group is replaced with an empty string — producing
broken alt/src in the rendered lightbox.

This is not XSS (output remains attribute-escaped), but it visibly mangles
legitimate content and is hard for site owners to diagnose.

Step-by-step reproduction

  1. Add an Image block to a post and enable its lightbox (Expand on click).
  2. Set the alt text to Only $1 today (or use an image whose filename
    contains $1, e.g. price-$1.jpg).
  3. View the post on the front end.
  4. Inspect the rendered <img>: the $1 is gone, e.g. alt="Only today".

Expected behaviour

The alt text and src should render exactly as authored, regardless of any
$N/\N sequences they contain.

Actual behaviour

Any $N/\N sequence in an img attribute is stripped/corrupted in the
lightbox output because it is treated as a regex backreference.

Proposed fix

A core/image block contains exactly one <img>, so a literal replacement
is sufficient and safe:

if ( isset( $img[0] ) ) {
    $body_content = str_replace( $img[0], $button, $body_content );
}

(Alternatively, inject the button through the existing WP_HTML_Tag_Processor
flow instead of regex.)

Environment

  • WordPress:
  • Gutenberg: <version, if applicable>
  • File: wp-includes/blocks/image.php — block_core_image_render_lightbox()

Step-by-step reproduction instructions

  1. Add an Image block to a post and enable its lightbox (Expand on click).
  2. Set the alt text to Only $1 today (or use an image whose filename
    contains $1, e.g. price-$1.jpg).
  3. View the post on the front end.
  4. Inspect the rendered <img>: the $1 is gone, e.g. alt="Only today".

Screenshots, screen recording, code snippet

No response

Environment info

No response

Please confirm that you have searched existing issues in the repo.

  • Yes

Please confirm that you have tested with all plugins deactivated except Gutenberg.

  • Yes

Please confirm which theme type you used for testing.

  • Block
  • Classic
  • Hybrid (e.g. classic with theme.json)
  • Not sure

Metadata

Metadata

Labels

[Block] ImageAffects the Image Block[Status] In ProgressTracking issues with work in progress[Type] BugAn existing feature does not function as intended

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions