Browse Source

Merge pull request #10537 from qazbnm456/improve-content_scripts.css

[Security] Use textContent instead innerHTML to remediate DOM based XSS
John Kleinschmidt 7 years ago
parent
commit
beb06c0787
1 changed files with 29 additions and 9 deletions
  1. 29 9
      lib/renderer/content-scripts-injector.js

+ 29 - 9
lib/renderer/content-scripts-injector.js

@@ -5,7 +5,7 @@ const {runInThisContext} = require('vm')
 // https://developer.chrome.com/extensions/match_patterns
 const matchesPattern = function (pattern) {
   if (pattern === '<all_urls>') return true
-  const regexp = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$')
+  const regexp = new RegExp(`^${pattern.replace(/\*/g, '.*')}$`)
   const url = `${location.protocol}//${location.host}${location.pathname}`
   return url.match(regexp)
 }
@@ -14,7 +14,7 @@ const matchesPattern = function (pattern) {
 const runContentScript = function (extensionId, url, code) {
   const context = {}
   require('./chrome-api').injectTo(extensionId, false, context)
-  const wrapper = `(function (chrome) {\n  ${code}\n  })`
+  const wrapper = `((chrome) => {\n  ${code}\n  })`
   const compiledWrapper = runInThisContext(wrapper, {
     filename: url,
     lineOffset: 1,
@@ -23,6 +23,23 @@ const runContentScript = function (extensionId, url, code) {
   return compiledWrapper.call(this, context.chrome)
 }
 
+const runStylesheet = function (url, code) {
+  const wrapper = `((code) => {
+    function init() {
+      const styleElement = document.createElement('style');
+      styleElement.textContent = code;
+      document.head.append(styleElement);
+    }
+    document.addEventListener('DOMContentLoaded', init);
+  })`
+  const compiledWrapper = runInThisContext(wrapper, {
+    filename: url,
+    lineOffset: 1,
+    displayErrors: true
+  })
+  return compiledWrapper.call(this, code)
+}
+
 // Run injected scripts.
 // https://developer.chrome.com/extensions/content_scripts
 const injectContentScript = function (extensionId, script) {
@@ -35,19 +52,22 @@ const injectContentScript = function (extensionId, script) {
         process.once('document-start', fire)
       } else if (script.runAt === 'document_end') {
         process.once('document-end', fire)
-      } else if (script.runAt === 'document_idle') {
+      } else {
         document.addEventListener('DOMContentLoaded', fire)
       }
     }
   }
 
   if (script.css) {
-    for (const {code} of script.css) {
-      process.once('document-end', () => {
-        var node = document.createElement('style')
-        node.innerHTML = code
-        window.document.body.appendChild(node)
-      })
+    for (const {url, code} of script.css) {
+      const fire = runStylesheet.bind(window, url, code)
+      if (script.runAt === 'document_start') {
+        process.once('document-start', fire)
+      } else if (script.runAt === 'document_end') {
+        process.once('document-end', fire)
+      } else {
+        document.addEventListener('DOMContentLoaded', fire)
+      }
     }
   }
 }