Make WordPress Core

Opened 5 days ago

Last modified 4 days ago

#63149 new defect (bug)

safecss_filter_attr does not support base64 SVG image in background-image.

Reported by: jamal59's profile jamal59 Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 6.7.2
Component: Formatting Keywords: has-patch has-unit-tests dev-feedback
Focuses: Cc:

Description

Hi,
I want to use "base64 SVG image" as background-image but the function does not work properly.

<?php
$css = "background-image: url('data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNDggNDgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGNpcmNsZSBmaWxsPSIjMDBmIiBjeD0iMjQiIGN5PSIyNCIgcj0iMTUiLz48L3N2Zz4='), url('data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNDggNDgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHJlY3QgZmlsbD0iI2YwMCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4IiAvPjwvc3ZnPgo=')";
echo '<span style="' . safecss_filter_attr( $css ) . '"></span>';

//output: <span style="background-image: url('data:image/svg+xml"></span>

The following codes are used in the safecss_filter_attr function to break the CSS, but because base64 uses two characters ":" and ";" the function does not work properly.

data:image/svg+xml;base64,PHN...

<?php
$css_array = explode( ';', trim( $css ) );

.
.
.

if ( ! str_contains( $css_item, ':' ) ) {
        $found = true;
} else {
        $parts        = explode( ':', $css_item, 2 );

regards

Change History (7)

#1 follow-up: @SirLouen
5 days ago

  • Keywords 2nd-opinion added

Hello @jamal59,
Welcome to Trac

I'm assuming that you are trying to santize the css, but there is a problem here with SVG: They can contain javascript code being potentially dangerous for a XSS attack.

Therefore, as far as I know, you should be doing the heavylifting when you want to deal with SVG
If you still want to permit SVG because you feel they are in a safe environment, there a filter called `safe_style_css` that might be handy in this situation to "deactivate" the safe_filter_attr for example for, background-image. Then you could do the sanitizing by yourself using some placeholders instead of the SVG and str_replace to put them back after the safecss_filter_attr

Also, I recommend you to check this plugin's code: https://github.com/10up/safe-svg

#2 @sabernhardt
5 days ago

  • Component changed from Security to Formatting

Related: #55452 (breaking on a semicolon)

This ticket was mentioned in PR #8567 on WordPress/wordpress-develop by @SirLouen.


4 days ago
#3

  • Keywords has-patch has-unit-tests added

Coming from this report:
https://core.trac.wordpress.org/ticket/55452

I've figured out that possibly this patch could solve, on an inner level the issues behind HTML encoded characters when sanitizing.
Not sure if this patch may sort this issue, because I still feel that problem with SVG could go beyond (the XSS problem). So I have no tested against this specific scenario, but I think I could bring this patch for attention.

Trac ticket: https://core.trac.wordpress.org/ticket/63149

#4 in reply to: ↑ 1 ; follow-up: @jamal59
4 days ago

Replying to SirLouen:

Hello @jamal59,
Welcome to Trac

I'm assuming that you are trying to santize the css, but there is a problem here with SVG: They can contain javascript code being potentially dangerous for a XSS attack.

Therefore, as far as I know, you should be doing the heavylifting when you want to deal with SVG
If you still want to permit SVG because you feel they are in a safe environment, there a filter called `safe_style_css` that might be handy in this situation to "deactivate" the safe_filter_attr for example for, background-image. Then you could do the sanitizing by yourself using some placeholders instead of the SVG and str_replace to put them back after the safecss_filter_attr

Also, I recommend you to check this plugin's code: https://github.com/10up/safe-svg

Hi, Thank you @SirLouen, If I use a PNG or GIF image instead of SVG, the function still doesn't work properly.

background-image: url('data:image/png;base64,iVBORw0KGgoAAAA

The safecss_filter_attr function doesn't work with images of type "inline data URI" as CSS background-image, Even if the images are PNG or GIF.

Also, I saw in the link below that if SVG is used as CSS background-image, the browser won't execute the JavaScript code inside it, I don't know how accurate or technical it is.
http://www.schepers.cc/svg/blendups/embedding.html

regards

#5 in reply to: ↑ 4 ; follow-up: @SirLouen
4 days ago

Replying to jamal59:

Also, I saw in the link below that if SVG is used as CSS background-image, the browser won't execute the JavaScript code inside it, I don't know how accurate or technical it is.
http://www.schepers.cc/svg/blendups/embedding.html

I think that the security issue depends on the browser, we cannot control which browser is using the user, and generally WP tends to maintain a big degree of compatibility with most browsers. And still I'm not confident if there is actually a protection for this in the code, it's just an hypothesis.

Hi, Thank you @SirLouen, If I use a PNG or GIF image instead of SVG, the function still doesn't work properly.

About base64 images in general, I've tested with this base64 image in the background:
https://i.imgur.com/cN7qeh5.png

And it renders adequately

https://i.imgur.com/6a4yMf0.png

The code block I used in the example

<!-- wp:media-text {"mediaId":null,"mediaType":"image","imageFill":true,"focalPoint":{"x":"0.75","y":"0.72"}} -->
<div class="wp-block-media-text alignwide is-stacked-on-mobile is-image-fill"><figure class="wp-block-media-text__media" style="background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=");background-position:75% 72%"><img src="https://developers.elementor.com/docs/assets/img/elementor-placeholder-image.png' alt="" /></figure><div class="wp-block-media-text__content"><!-- wp:paragraph {"placeholder":"Content…","fontSize":"medium"} -->
<p class="has-medium-font-size">"<a rel="noreferrer noopener" href="https://www.rawpixel.com/image/430579/free-photo-image-palm-tree-palm-africa" target="_blank">Palm trees at Cape Town, South Africa</a>" by Scott Webb is marked with <a rel="noreferrer noopener" href="https://creativecommons.org/publicdomain/zero/1.0/?ref=openverse" target="_blank">CC0 1.0</a>.</p>
<!-- /wp:paragraph --></div></div>
<!-- /wp:media-text -->

#6 @SirLouen
4 days ago

  • Keywords dev-feedback added; 2nd-opinion removed

#7 in reply to: ↑ 5 @jamal59
4 days ago

Replying to SirLouen:

The code block I used in the example

Hi, Thank you @SirLouen, Please test with the block below. everything is fine in the editor, but the image is not displayed in the frontend.

<!-- wp:read-more {"content":"read more <span  style=\"display: inline-block;background-size: 100% 100%;width:48px;height:48px;background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=');\"></span> "} /-->

It seems that the safecss_filter_attr function is not called for some blocks.

I want to add a new format to the Gutenberg Rich text (using the registerFormatType function). This new format adds a span tag with background image.
Everything works fine with blocks like paragraph or heading but not with blocks like navigation menu and Read More. Actually everything is fine in editor but it is not displayed in frontend.

After checking I found out that the problem is with the safecss_filter_attr function which doesn't work properly with base64 images data URI.

regards

Note: See TracTickets for help on using tickets.