apostrophecms / sanitize-html

Clean up user-submitted HTML, preserving whitelisted elements and whitelisted attributes on a per-element basis. Built on htmlparser2 for speed and tolerance
MIT License
3.79k stars 353 forks source link

Cannot allow SVGs elements to get working #489

Closed jozef-rzadkosz closed 8 months ago

jozef-rzadkosz commented 3 years ago

Step by step instructions to reproduce the behavior:

  1. Create a SVG element with some gradient inside
  2. Insert the code as v-html in Vue e.g.
  3. Set allowedTags to: ['svg','g','use','defs','path','linearGradient', 'stop']
  4. Set allowedAttributes to: ['*']
  5. See that gradient elements are not rendered in latest Chrome or Safari

Expected behavior

Gradient should be visible

Describe the bug

Elements with gradient are not rendered, on Safari I am getting black instead of gradients

Details

When I set allowedAttributes and allowedTags to false everything is working properly, is that risky operation?

abea commented 3 years ago

Do you mean you have allowedAttributes as something like { 'svg': ['*'] }? With only the array that wouldn't work. Or you could use false to allow all attributes on anything (probably not a great idea).

I do see a possible issue with viewBox and linearGradient where they might become fully lower-cased. Actually linearGradient seems rejected when camel cased. If I add 'lineargradient' to the allowed tags it gets through lowercased. This could be a htmlparser2 thing.

A failing test:

  it('should support SVG tags', () => {
    assert.equal(sanitizeHtml('<svg viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient id="myGradient" gradientTransform="rotate(90)"><stop offset="5%" stop-color="gold"></stop><stop offset="95%" stop-color="red"></stop></linearGradient></defs><circle cx="5" cy="5" r="4" fill="url(\'#myGradient\')"></circle></svg>', {
      allowedTags: [ 'svg', 'g', 'defs', 'linearGradient', 'lineargradient', 'stop', 'circle' ],
      allowedAttributes: false
    }), '<svg viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient id="myGradient" gradientTransform="rotate(90)"><stop offset="5%" stop-color="gold"></stop><stop offset="95%" stop-color="red"></stop></linearGradient></defs><circle cx="5" cy="5" r="4" fill="url(\'#myGradient\')"></circle></svg>');
  });

That's an svg from the MDN article on linearGradient.

abea commented 3 years ago

It looks like disabling lowercasing in the htmlparser2 options might be a way to go when you know you're using SVGs. https://github.com/fb55/htmlparser2/issues/539#issuecomment-687579675

jozef-rzadkosz commented 3 years ago

I cannot add svg in allowedAttributes object, everything is working but with svg I am getting Error isPlainObject and this is caused only by svg without it everything is working but gradient is not being displayed

allowedAttributes: { path: ['d', 'fill'], svg: ['viewBox', 'viewbox'], linearGradient: [ 'id', 'x1', 'x2', 'y1', 'y2', 'gradientUnits', 'gradientunits', ], stop: ['stop-color', 'offset'], },

I got fully working example by setting lowerCase to true but still allowedAttributes is set to false, any ideas?

Working example: sanitizeHtml(text, { allowedTags: [ 'svg', 'linearGradient', 'lineargradient', 'path', 'stop', ], allowedAttributes: false, lowerCase: true, });

BoDonkey commented 8 months ago

Closed by PR #646