<p dir="auto"><strong>Do you want to request a <em>feature</em> or report a <em>bug</em>?</strong><br>
I would like to request a bug.</p>
<p dir="auto"><strong>What is the current behavior?</strong><br>
From what I know, it is possible to inject object in props. However, this object seems to be html escaped when inserted into the DOM from my observation.</p>
<p dir="auto">Thus, if I try to add an onerror=alert('XSS') in a &lt;img {this.props.dangerousAtt /&gt; tag through a props, this is gonna be escaped when rendered. Then, I realized that inserting an id='test' is totally possible with a props. So I thought only dangerous javascript injectable attributes are escaped such as onerror,  onload, ...</p>
<p dir="auto">However, I realized that the href=javascript:alert('1') is not escaped when inserted through a props. The javascript gets executed. Here, I thought it might a bug.</p>
<p dir="auto"><strong>If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React. Paste the link to your JSFiddle (<a href="https://jsfiddle.net/Luktwrdm/" rel="nofollow">https://jsfiddle.net/Luktwrdm/</a>) or CodeSandbox (<a href="https://codesandbox.io/s/new" rel="nofollow">https://codesandbox.io/s/new</a>) example below:</strong></p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="class App extends Component {
  render() {
  const href = {href: &quot;javascript:alert('1')&quot;};
    return (
      &lt;div&gt;
      &lt;a {...href}&gt;Click here&lt;/a&gt;     
      &lt;/div&gt;
    ); 
}

ReactDOM.render(&lt;App /&gt;, document.getElementById('root'));
"><pre class="notranslate"><code class="notranslate">class App extends Component {
  render() {
  const href = {href: "javascript:alert('1')"};
    return (
      &lt;div&gt;
      &lt;a {...href}&gt;Click here&lt;/a&gt;     
      &lt;/div&gt;
    ); 
}

ReactDOM.render(&lt;App /&gt;, document.getElementById('root'));

</code></pre></div>
<p dir="auto"><strong>What is the expected behavior?</strong></p>
<p dir="auto">I would expect the href object to be escaped as a props, so being treated exactly like onerror or other javascript attributes.</p>
<p dir="auto"><strong>Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?</strong><br>
React version: 16.6.0<br>
Browser: Chrome 70.0.3538.77</p>
<p dir="auto"><strong>Do you want to request a <em>feature</em> or report a <em>bug</em>?</strong></p>
<p dir="auto">A bug, but a well known and worked-around one.</p>
<p dir="auto"><strong>What is the current behavior?</strong></p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="var x = 'javascript:alert(1)';
ReactDOM.render(
  (&lt;a href={x}&gt;Link&lt;/a&gt;),
  document.getElementById('container')
);"><pre class="notranslate"><span class="pl-k">var</span> <span class="pl-s1">x</span> <span class="pl-c1">=</span> <span class="pl-s">'javascript:alert(1)'</span><span class="pl-kos">;</span>
<span class="pl-v">ReactDOM</span><span class="pl-kos">.</span><span class="pl-en">render</span><span class="pl-kos">(</span>
  <span class="pl-kos">(</span><span class="pl-c1">&lt;</span><span class="pl-ent">a</span> <span class="pl-c1">href</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-s1">x</span><span class="pl-kos">}</span><span class="pl-c1">&gt;</span>Link<span class="pl-c1">&lt;</span><span class="pl-c1">/</span><span class="pl-ent">a</span><span class="pl-c1">&gt;</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
  <span class="pl-smi">document</span><span class="pl-kos">.</span><span class="pl-en">getElementById</span><span class="pl-kos">(</span><span class="pl-s">'container'</span><span class="pl-kos">)</span>
<span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div>
<p dir="auto">produces a link that alerts.</p>
<p dir="auto"><strong>If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React. Paste the link to your JSFiddle (<a href="https://jsfiddle.net/Luktwrdm/" rel="nofollow">https://jsfiddle.net/Luktwrdm/</a>) or CodeSandbox (<a href="https://codesandbox.io/s/new" rel="nofollow">https://codesandbox.io/s/new</a>) example below:</strong></p>
<ul dir="auto">
<li><a href="https://jsfiddle.net/Luktwrdm/202/" rel="nofollow">Load the code above in the codepen REPL</a></li>
<li>After the REPL loads, click the "Run" button at the top left.</li>
<li>You should see a blue "link" in the bottom-right pane.</li>
<li>Click it.  An alert will popup.</li>
</ul>
<p dir="auto">The alert should not pop up.</p>
<p dir="auto">A simple string that reaches an <code class="notranslate">href</code> attribute should not cause arbitrary code execution even with user interaction.</p>
<p dir="auto"><strong>What is the expected behavior?</strong><br>
A string that reaches a browser builtin like the <code class="notranslate">HTMLAElement.prototype.href</code> setter should not cause code execution.</p>
<p dir="auto"><strong>Discussion</strong></p>
<p dir="auto"><a href="https://docs.google.com/presentation/d/1hepAXMroHSNTM0NV1aGlntjHrw0a0QOM5X5JvfXv_N0/edit#slide=id.g227691820f_0_198" rel="nofollow">Polymer Resin</a> uses hooks in another webcomponents framework to intercept value before they reach browser builtins where they can be vetted.  A similar approach could work for React.</p>
<p dir="auto">It allows values to reach browser builtins when they are innocuous or have a runtime type that indicates that the author intentionally marked them as safe for that kind of browser builtin.</p>
<p dir="auto">For example, an <code class="notranslate">instanceof SafeURL</code> would be allowed to reach <code class="notranslate">HTMLAElement.prototype.href</code> as would any string that is a relative URL, or one with a whitelisted protocol in (<code class="notranslate">http</code>, <code class="notranslate">https</code>, <code class="notranslate">mailto</code>, <code class="notranslate">tel</code>) but not <code class="notranslate">javascript:...</code>.</p>
<p dir="auto">Many developers know that <code class="notranslate">&lt;a href={...}&gt;</code> is risky, but if the link is an implementation detail of a custom React element, then developers don't have the context to know which attributes they need to be careful with.  They shouldn't have to either since it is an implementation detail.</p>
<p dir="auto"><strong>Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?</strong></p>
<p dir="auto">I believe this is widespread across versions.</p>
<p dir="auto">An earlier REPL I tried showed that it worked on version 16.2.0 from <a href="https://unpkg.com/react-dom/umd/react-dom.development.js" rel="nofollow">https://unpkg.com/react-dom/umd/react-dom.development.js</a> but I don't know what version the jsfiddle above uses.</p>