13

I am trying to run the following:

chrome.tabs.onCreated.addListener(function (tab){
    if (tab.url.indexOf(".salesforce.com/") != -1 || tab.url.indexOf(".force.com/") != -1) {
        chrome.tabs.executeScript(tab.id, {
            "file": "loadScript.js"
        }, function () {
            console.log("Script Executed .. ");
        });
    } else {
        var wrongTab = chrome.i18n.getMessage("wrongTab");
        console.log(wrongTab);
        alert(wrongTab);
    }
});

Which should (in theory), on page load run the loadScript.js file.... the loadScript.js file is as follows, this should append a file to the running page, not to the background page as it is at the moment:

/* Create a scriipt element in head of HTML and put /soap/ajax/31.0/connection.js in the src  */
var connectJsUrl = "/connection.js";

function loadScript(url, callback) {
    var head = document.getElementsByTagName("head")[0];
    var script = document.createElement("script");
    script.src = url;
    var done = false;
    script.onload = script.onreadystatechange = function() {
        if (!done && (!this.readyState || this.readyState == "loaded" || this.readyState == "complete")) {
            done = true;
            callback();
            script.onload = script.onreadystatechange = null;
            head.removeChild(script);
        }
    };
    head.appendChild(script);
}

loadScript(connectJsUrl, function() {
    console.log("Script Confirmed...")
});

/* Check to see if the file have been appended correctly and works correctly */
var JSFile = "chrome-extension://" + window.location.host + connectJsUrl;
var req = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
if (req == null) {
    console.log("Error: XMLHttpRequest failed to initiate.");
};
req.onload = function() {
    try {
        eval(req.responseText);
    } catch (e) {
        console.log("There was an error in the script file.");
    }
};
try {
    req.open("GET", JSFile, true);
    req.send(null);
} catch (e) {
    console.log("Error retrieving data httpReq. Some browsers only accept cross-domain request with HTTP.");
};

I am still a newbie to Chrome Extensions and .js so excuse me if I have made a stupid mistake :)

All I am getting from this is the following: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' chrome-extension-resource:".

Tim
  • 649
  • 1
  • 5
  • 21

4 Answers4

23

To prevent cross site scripting Google has blocked the eval function.

To solve this add this code to the manifest.json

"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",

Please comment if you need further explanation

hoefling
  • 59,418
  • 12
  • 147
  • 194
abhilash
  • 827
  • 11
  • 20
6

IMPORTANT

As mentioned before add this to your manifest.json:

"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"

Make sure you set the "manifest_version" to 2 aka

//this
"manifest_version": 2

Chrome Extentions that work on manifest_version 3 don't support unsafe evals for some security reasons.

Also make sure to reload your extention.

  • 1
    manifest v2 is being deprecated. All new extensions need to be v3 (enforced by chrome store) – TKrugg Aug 07 '22 at 23:10
2

For Manifest V3

You cannot run code with unsafe eval in manifest v3 , if you are using any bundlers like webpack or vite , you can change the code not to use eval or check package bundle if it contains any eval , here are the list of syntax you are not suppose to use in manifest 3

  • eval()
  • setTimeout()
  • setInterval()
  • Function()
  • setImmediate()
  • execScript()

It is not safe to add content_security_policy with unsafe-eval as site may be prone to XSS attack

But If you are using any wasm code by chance then below config will work to avoid eval for manifest 3

"content_security_policy": {
   "extension_page":"script-src 'self' 'wasm-unsafe-eval'; object-src 'self'"
}

If you are using any iframe add below code also

"content_security_policy": {
   "extension_page":"script-src 'self' 'wasm-unsafe-eval'; object-src 'self'",
   "sandbox":"script-src 'self' 'wasm-unsafe-eval'; object-src 'self'"
}
Goutham J.M
  • 1,726
  • 12
  • 25
0

After experimenting, I found out that running a web server hosting an html file (that is running your eval) will still work. Then, send the results to the parent window and done.

CLIENT:

var elm = document.createElement('iframe');
elm.src = 'http://localhost:3000'; // I used a basic expressJS server
document.body.appendChild(elm);

SERVER:

const express = require('express');
const socketIO = require('socket.io'); // Optional
const http = require('http');
const path = require('path');


const app = express();
let server = http.createServer(app);
let io = socketIO(server);

const publicPath = path.resolve(__dirname, '../public');
const port = process.env.PORT || 3000;

app.use(express.static(publicPath));

io.on('connection', (client) => {
    console.log('User connected');
});

server.listen(port, (err) => {
    if (err) throw new Error(err);
    console.log(`Server running on port ${port}`);
});

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Test</title>
</head>
<body>
    <script>
        eval(alert('test'))
    </script>

    <!-- Other html.. -->
</body>
</html>