How to use `eval` in a V3 chrome extension

Lucas Calje
Geek Culture
Published in
2 min readJun 7, 2022

--

Chrome Extension developers these days are slowly migrating their code from V2 to V3, which unfortunately, isn’t always a straightforward job.

One of the problems I see developers struggling with is how they should migrate eval. This was also the case when I migrated my own extension which uses eval all over the place. This is the error you get in V3

Error in event handler: EvalError: 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'".

In V2 it was possible to use eval everywhere, but in V3 you can’t use it anywhere. But luckily, there is a solution to work around this issue, which is described here

V3 sandbox documentation

Unfortunate, the solution described is directly copied from V2 and it doesn’t work out of the box very well. It describes how you can sandbox your eval code using an iframe inside the background script. Running the iframe solution in the background script was a perfect solution in V2, but not anymore in V3, as the background script is a service worker. It can’t create iframes. So, the solution is simple, just create the iframe somewhere else (except the content script). In my case I used my popup html file and added the following html code

<iframe src=”../sandbox.html” id=”sandbox” style=”display: none”></iframe>

where sandbox.html contains the code which executes theeval

<html>
<script>
window.addEventListener('message', async function (event) {
event.source.window.postMessage(eval(event.data), event.origin);
});
</script>
</html>

And don’t forget to configure sandbox.html as true sandbox

"sandbox": {
"pages": [
"sandbox.html"
]
}

This should be added to the manifest.json file.

And finally, the code which communicates with the sandbox

const iframe = document.getElementById('sandbox');window.addEventListener('message', (event) => {
console.log('EVAL output', event.data);
});
iframe.contentWindow.postMessage('10 + 20', '*');

Thats it. Cheers

--

--