A while back someone (who shall remain anonymous because I have made this type of category mistake before) someone opened an issue for an ajax library I have, complaining about the security risks related to using eval as a fallback to parse JSON if someone had a browser that didn’t support JSON.parse. What was notable was that the library also supports JSONP which the issue made no note of.
So why does eval (and friends like Function and SetTimeout with a string) get so much FUD exactly, it’s not just the security, preventing eval doesn’t do much good when any script can add arbitrary script tags, I mean your closing the barn doors after the sheep cows have left if your preventing the Function constructor on page that has jQuery (with it’s $.jsonp).
This is not to say that there are no security issues, there are but you can’t deal with them by just avoiding eval, CSP are the way to do that, they can prevent pretty much everything I talk about here, except maybe the blob worker through I’m not sure. But they are beyond the scope of this article.
One reason has to do with historical misuse of eval, take a look at this snippet which is honest to god in the wild code
This file (
which is downloaded with a bunch of files which start with ‘dnn’ someone is going to figure it out, it’s this script, from this page part of Dot Net Nuke CMS site) uses eval nearly 340 times for string concatenation. 340 times they create a new instance of the virtual machine in order … in order to do nothing, the script will act exactly the same without the eval (except be faster).
Brendan Eich mentioned how back in the day, people wouldn’t realize you could do obj[key] and instead would do eval(“obj.”+key).
This is the reason eval is ‘evil’, because unless you actually know what you are doing, you’re more likely to shoot your self in the foot then anything else so for all intensive purposes you should consider it evil and move along.
eval and friends
While eval is well known, when we are talking about eval we are actually talking about a couple things, first you have the Function constructor. new Function(arg1, arg2, string) creates a new function with the last argument as the body and the other arguments as the functions arguments. In essence it’s this.
So you’re running eval on the body of it. The other ‘classic’ evalesque functions are setInterval and setTimeout when you give it a string in the first argument instead of a function. Unlike the function constructor which occasionally has some legit uses passing a string to setTimeout and setInterval doesn’t, ever.
Using the DOM isn’t as bad as the previous methods performance wise as it doesn’t create a new VM, and when creating a working a new VM is the point so it’s a legit trade off. Workers are somewhat less of a risk as they have no access to the DOM, and can only message the main thread but now execute anything, on the other hand workers can do ajax requests and can load scripts via the importScripts function and run eval so security wise there are trade offs.
When eval isn’t evil
Until the ES6 proxy object eval was the only way meta program. For instance in CouchDB you write a function in the database which calls a function called ‘emit’ with the result. e.g.
Eval and it’s friends, mostly blob workers are used extensively by Catiline, a library which creates new creates a new API on top of web workers which allow them to be used easier in libraries but also with fall backs that don’t support workers. In order to be able to write a function in current scope, but run inside a web worker is by using the toString method of functions and then running regexes on them before opening them in the worker (or iframe as a fallback).
The function constructor can be used to make very fast templates as it uses the constructor to create a function which concats strings and nothing else.
Axel Rauschmayer points out that eval can be very effective in carefully controlled offline situations to make config files much more expressive.
Thomas gratier pointed me to an article by Nick Zakas on using eval in a css parser.
Regex + eval as a combination can allow meta programming as powerful as macros in other languages. Of course these are unhygienic as hell (but this never stopped certain LISPs) and have some major performance penalties so you while you can do amazing things with regex + eval you can also shoot yourself in the foot.
In other words if you don’t know what you’re doing, you should just go ahead and consider eval evil, but if you do, and your careful, you can do some amazing things.