gregberge / svgr

Transform SVGs into React components 🦁
https://react-svgr.com
MIT License
10.59k stars 422 forks source link

The project might introduce XSS #912

Open oriSomething opened 1 year ago

oriSomething commented 1 year ago

🐛 Bug Report

SVGR doesn't seems to contain any option to sanitize SVGs Screenshot 2023-10-17 at 9 23 37

To Reproduce

Just add <script> with the wanted XSS inside the .svg file. (There are more way to introduce XSSs in SVGs).

Expected behavior

The result expected to be clean from inline scripts, problematic styles and inline events.

Link to repl or repo (highly encouraged)

N / A

Run npx envinfo --system --binaries --npmPackages @svgr/core,@svgr/cli,@svgr/webpack,@svgr/rollup --markdown --clipboard

It's from Playground

oriSomething commented 1 year ago

It should be added, many people use random SVGs from the web without checking their content, and this is why the fact it possible, it's something that at least should be in bold in the README

SethFalco commented 1 year ago

SVGO does include the removeScriptElement plugin which may help. Documentation: https://svgo.dev/docs/plugins/remove-scripts/

The plugin ID is due to be renamed to removeScripts in a future version, but in v3.0.3, this already removes <script> elements, event attributes (onload, onclick, oninput, etc), and JavaScript URIs in href attributes.

Feedback welcome if you're aware of other ways to run scripts in an SVG.

If the repository were to act on this issue, I'd advise adding a notice recommending that users use that plugin, or seek another sanitization library.

Example

original.svg

<svg viewBox="0 0 256 172" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid">
  <script>alert('😈')</script>
  <g onclick="alert('😈!')">
    <path d="M112.973416,9.2496789 C105.800602,-3.0832263 87.8689954,-3.0832263 80.6961815,9.2496789 L2.52446046,143.659628 C-4.64826776,155.992961 4.3176211,171.408985 18.6631204,171.408985 L79.688321,171.408985 C73.5584906,166.051862 71.2883417,156.784087 75.9271555,148.832569 L135.130926,47.3479175 L112.973416,9.2496789 Z" fill="#80EEC0"></path>
  </g>
  <a href="javascript:(() => { alert('😈!!') })();">
    <path d="M162.504638,38.7329166 C168.440863,28.6423189 183.280784,28.6423189 189.217009,38.7329166 L253.910685,148.704498 C259.84691,158.795096 252.42695,171.408557 240.554499,171.408557 L111.167148,171.408557 C99.295126,171.408557 91.8747374,158.795096 97.8109626,148.704498 L162.504638,38.7329166 Z" fill="#00DC82"></path>
  </a>
</svg>

svgo.config.js

module.exports = {
  plugins: [
    "removeScriptElement",
  ]
};

optimized.svg

<svg viewBox="0 0 256 172" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid">
  <g>
    <path d="M112.973416,9.2496789 C105.800602,-3.0832263 87.8689954,-3.0832263 80.6961815,9.2496789 L2.52446046,143.659628 C-4.64826776,155.992961 4.3176211,171.408985 18.6631204,171.408985 L79.688321,171.408985 C73.5584906,166.051862 71.2883417,156.784087 75.9271555,148.832569 L135.130926,47.3479175 L112.973416,9.2496789 Z" fill="#80EEC0"/>
  </g>
  <path d="M162.504638,38.7329166 C168.440863,28.6423189 183.280784,28.6423189 189.217009,38.7329166 L253.910685,148.704498 C259.84691,158.795096 252.42695,171.408557 240.554499,171.408557 L111.167148,171.408557 C99.295126,171.408557 91.8747374,158.795096 97.8109626,148.704498 L162.504638,38.7329166 Z" fill="#00DC82"/>
</svg>