title: CustomEvent.detail "tainted"?
body: <p>I'm developing a Chrome extension to add convenience to a website.<br>
  I have access to the page's DOM, but I also need to interact with the "first-party" JS on that page, which I cannot do from my extension.</p>
  
  <p>I can inject arbitrary tags into the page (most notably also <code>&lt;script&gt;</code> tags), but since escaping strings like</p>
  
  <pre><code>{
      html: '&lt;div onclick="doSomething(this, \'someName\')"&gt;&lt;/div&gt;'
  }
  </code></pre>
  
  <p>is a real pain, I'd like to keep the injected code at an absolute minimum.</p>
  
  <p>I tried injecting event listeners into the page in order to fetch JS variables from the page, but ran into a problem.<br>
  It seems that if a <code>CustomEvent</code> is passed from an extension to a website or back, and if <code>CustomEvent.detail</code> contains certain types of objects (at least functions and errors) somewhere, the entire <code>CustomEvent.detail</code> will be purged, i.e. set to null.  </p>
  
  <h1>Example</h1>
  
  <p>Script (extension.js):</p>
  
  <pre><code>(function()
  {
      var script = document.createElement('script');
      script.innerHTML = [
  "window.addEventListener('xyz', function(ev)",
  "    {                                      ",
  "        console.log('after dispatch:');    ",
  "        console.log(ev.detail);            ",
  "    });                                    ",
      ].join('\n');
      document.head.appendChild(script);
      // JSON-serializable data
      var e = new CustomEvent('xyz', { detail: { x: 42, name: 'Schroedinger' } });
      console.log('before dispatch:')
      console.log(e.detail);
      window.dispatchEvent(e);
      // non-JSON-serializable data
      var detail = { x: 42, name: 'Schroedinger' };
      detail.detail = detail; // Create circular reference
      e = new CustomEvent('xyz', { detail: detail });
      console.log('before dispatch:')
      console.log(e.detail);
      window.dispatchEvent(e);
      // data with function
      e = new CustomEvent('xyz', { detail: { x: 42, name: 'Schroedinger', func: function(){} } });
      console.log('before dispatch:');
      console.log(e.detail);
      window.dispatchEvent(e);
      // data with error object
      e = new CustomEvent('xyz', { detail: { x: 42, name: 'Schroedinger', err: new Error() } });
      console.log('before dispatch:');
      console.log(e.detail);
      window.dispatchEvent(e);
  })();
  </code></pre>
  
  <p>Output (paragraphed for readability):</p>
  
  <pre class="lang-none prettyprint-override"><code>before dispatch:
  Object {x: 42, name: "Schroedinger"}
  after dispatch:
  Object {x: 42, name: "Schroedinger"}
  
  before dispatch:
  Object {x: 42, name: "Schroedinger", detail: Object}
  after dispatch:
  Object {x: 42, name: "Schroedinger", detail: Object}
  
  before dispatch:
  Object {x: 42, name: "Schroedinger", func: function (){}}
  after dispatch:
  null
  
  before dispatch:
  Object {x: 42, name: "Schroedinger", err: Error at chrome-extension://...}
  after dispatch:
  null
  </code></pre>
  
  <p>I initially thought JSON-serializability was the issue, but circular references pass just fine in events, when they would break if JSON-serialized.<br>
  It feels like certain objects "taint" the event detail the same way <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image" rel="nofollow">non-crossorigin images taint canvases</a>, except there's nothing in the console.</p>
  
  <p>I was unable to find any documentation regarding this behaviour, and (as Paul S. suggested), there does not seem to be a "privilege" for that on the <a href="https://developer.chrome.com/extensions/declare_permissions" rel="nofollow">Chrome permissions list</a>.</p>
  
  <p>Tested in Chrome 40.0.2214.115m, 43.0.2357.124m and 48.0.2547.0-dev.</p>