Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[HTMLSanitizer] force_attributes not replacing existing attribute in initial data #58065

Copy link
Copy link
Open
@AppyGG

Description

@AppyGG
Issue body actions

Symfony version(s) affected

6.1, 6.2, 6.3, 6.4, 7.0, 7.1, 7.2

Description

In the HTMLSanitizer, the force_attributes definition does not work as described in the documentation or in the class.

If an attribute is already defined in the unsanitized html, it is not replaced by the value defined in configuration.

As definied in the Force Attributes Values documentation :

Using this option, you can force an attribute with a given value on an element. For instance, use the follow config to always set rel="noopener noreferrer" on each element (even if the original one didn't contain a rel attribute)

And in the HTMLSanitizerConfig class function forceAttribute :

/**
* Forcefully set the value of a given attribute on a given element.
*
* The attribute will be created on the nodes if it didn't exist.
*/

As i understand the documentation, the attribute value should be replaced if already existing.

How to reproduce

With the following HTMLSanitizer configuration :

// config/packages/html_sanitizer.yaml
framework:
    html_sanitizer:
        sanitizers:
            app.wysiwyg_sanitizer:
                allow_safe_elements: true
                force_https_urls: true
                allow_relative_medias: true
                allow_attributes:
                    border: '*'
                    class: '*'
                    src: ['img']
                    style: '*'
                force_attributes:
                    img:
                        loading: lazy

The initial string to be sanitized :
<img title="My image" src="https://example.com/image.png" loading="eager" onerror="alert('1234')" />

Should result to :
<img title="My image" src="https://example.com/image.png" loading="lazy" />

But it actually sanitized to :
<img title="My image" src="https://example.com/image.png" loading="eager" />

And with the initial string : <img title="My image" src="https://example.com/image.png" />
The loading=lazy attribute is correctly added : <img title="My image" src="https://example.com/image.png" loading="lazy"/>

To be sure it's replaced i need to add a drop_attributes entry to first drop existing loading attribute and then force it.

REPRODUCE

<?php

// $ composer require symfony/html-sanitizer

require_once __DIR__.'/vendor/autoload.php';

use Symfony\Component\HtmlSanitizer\HtmlSanitizer;
use Symfony\Component\HtmlSanitizer\HtmlSanitizerConfig;

// String containing a loading attribute (and other attributes to be sanitized)
$stringToSanitize1 = '<img title="My image" src="https://example.com/image.png" loading="eager" onerror="alert(\'1234\')" />';

// String NOT containing a loading attribute 
$stringToSanitize2 = '<img title="My image" src="https://example.com/image.png" />';

// Init htmlSanitizer with a basic config forcing "loading" attribute to the value "lazy" on images
$htmlSanitizer = new HtmlSanitizer(
    (new HtmlSanitizerConfig())->allowSafeElements()->forceAttribute('img', 'loading', 'lazy')
);

var_dump($htmlSanitizer->sanitize($stringToSanitize1));
// Result : string(76) "<img title="My image" src="https://example.com/image.png" loading="eager" />"

var_dump($htmlSanitizer->sanitize($stringToSanitize2));
// Result : string(75) "<img title="My image" src="https://example.com/image.png" loading="lazy" />"

Possible Solution

No response

Additional Context

Tested on :
"In Application" => Symfony 6.4.10, PHP 8.3, symfony/html-sanitizer 6.4.8

"Reproducer" => PHP8.3, symfony/html-sanitizer 7.1.1

Also a "workaround" is to add a drop_attributes configuration before forcing it.

// config/packages/html_sanitizer.yaml
framework:
    html_sanitizer:
        sanitizers:
            app.wysiwyg_sanitizer:
                allow_safe_elements: true
                force_https_urls: true
                allow_relative_medias: true
                allow_attributes:
                    border: '*'
                    class: '*'
                    src: ['img']
                    style: '*'
                drop_attributes:
                    loading: ['img']
                force_attributes:
                    img:
                        loading: lazy

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.