What are the security issues with "eval()" in JavaScript?

  • Every time that someone mentions eval(), everyone says that there are "security issues" with it, but nobody ever goes into detail about what they are. Most modern browsers seem to be able to debug eval() just as well as normal code, and people's claims of a performance decrease are dubious/browser dependent.

    So, what are the issues, if any, associated with eval()? I haven't been able to come up with anything that could be exploited with eval() in JavaScript. (I do see issues with eval()'ing code on the server, but client-side eval() seems to be safe.)

    Client-side eval is only safe if you know the contents being passed come from the client performing the execution.

    Also only if you know they were not modified between the time the client generated them and the time the browser executes them.

    @S.C. Modified by whom, on what basis? In general, it is impossible harden a program against the end-user messing with its state with a debugger. But if it was modified by adding something that came from somewhere other than the client then obviously that would mean the contents don't come from the client anymore.

    @Random832, you are correct in that a developer should always assume the presentation layer can be modified by the client. They can break their own session and you shouldn't have to care about that. In practice, even if a client is not in an isolated, sterile environment, there is very little that could make a dangerous change without the previous existence of another compromise on the client's side (plugin, MITM, cache, physical access, etc). In theory, if you are not actively securing against it it is possible. How you want to balance practice and theory is up to you and your organization.

    What research have you done? Reasons to be wary of eval are described in a number of places. "nobody ever goes into detail about what they are" - Citation needed. This is clearly false. Just do a search on "eval" on this site and you'll find a bunch of posts that provide various levels of detail about risks with eval. See, e.g., http://security.stackexchange.com/q/25642/971, http://security.stackexchange.com/q/30365/971, http://security.stackexchange.com/a/90764/971, http://security.stackexchange.com/q/23192/971, to list a few I came across immediately.

  • eval() executes a string of characters as code. You use eval() precisely because the string contents are not known in advance, or even generated server-side; basically, you need eval() because the JavaScript itself will generate the string from data which is available only dynamically, in the client.

    Thus, eval() makes sense in situations where the JavaScript code will generate code. This is not intrinsically evil, but it is hard to do securely. Programming languages are designed to allow a human being to write instructions that a computer understands; to that effect, any language is full of small quirks and special behaviours that are supposed to help the human programmer (e.g. the automatic adding of ';' at the end of some statements in JavaScript). This is all nice and dandy for "normal" programming; but when you generate code from another program, based on data which may be potentially hostile (e.g. string excerpt from other site users), then you have to, as the developer for the code generator, know about all these quirks, and prevent hostile data to exploit them in damaging ways.

    In that sense, code generators (and thus eval()) incur the same conceptual issues as raw SQL and its consequence, SQL injection attacks. Assembling at runtime an SQL request from externally provided parameters can be done securely, but this requires minding an awful lot of details, so the usual advice is not to do that. This relates to the usual conundrum of security, i.e. that it is not testable: you can test whether some piece of code works properly on correct data, but not that it never works improperly on incorrect data. Similarly, using eval() securely is possible, but it is so hard in practice that it is discouraged.

    All of this is said in all generality. In your specific context, eval() might be safe. However, it takes some effort to have a context safe for use of eval(), that actually needs eval().

    Isn't `eval()` also prevalent in XSS attacks?

    Can you give a more specific example of how this would occur? I get that eval() executes a string, but I'd like to know what's uniquely problematic about it. A user can already run arbitrary JS through the console, and so I'm wondering what's different about the danger posed by eval().

    The difference is in where the eval contents comes from. If the string contents being passed to the eval call have the potential to be influenced in one way or another by a user or pulled from the database onto a page of more than just the one user who sourced those contents, you have a possibility for XSS. If you are just letting the user execute arbitrary JS within their own session, no harm done unless someone else can somehow influence the contents again. This is similar to dynamically generating javascript on the server side with unfiltered values sourced by user input.

    So, effectively, there is only a problem when several other parts of your system have been compromised? Of course, most of the usefulness of eval involves running scripts either written by the server, or scripts pulled from a database, in which case you just have to trust the DB.

    Close but not necessarily. Suppose you run a site that lets me create content other users can see. Further suppose it lets me choose from a set of custom UI transitions to go along with that content and after investigation I find that set actually correlates to function names used in an eval statement. If I can find a way to append arbitrary JS to the transition code being executed, you will end up with a persistent XSS attack vector because I'm able to cause arbitrary JS to execute in the browser of anyone who view that content. That vulnerability would not exist if you didn't use eval.

    Bottom line is you are going to cause unknown code to execute in the users browsers. You can do your best to ensure it is safe code or code only from an accepted set of sources or behaviors, but at the end of the day you are still dealing with the principle of being as sure as you can be that nothing bad will execute as opposed to knowing for certain you do not provide the ability to execute anything harmful. If your scenario is simple enough that you can be sure it is always safe, it is almost always simple enough that you don't really need eval() at all.

    @S.C. What if we can assume that everyone with the ability to add those "UI Transitions" can be trusted? What if it were only available to administrators (or equivalent)?

    Then you have progressed towards securing it by locking down its usage but still have several other avenues through which it could turn dangerous. Suppose another developer inherits your code and doesn't realize the requirements for keeping its usage secure -- how long do you think it will stay reasonably secure as he maintains the codebase? Suppose the I can find an injection in the selection/setting of the used transition instead of just in the adding of them (i.e. eval("someTransitionISelected();/*now do some evil stuff*/"))? Suppose you copy/paste for something similar but don't restrict?

    You then have to consider cost. What is the cost to implement and then maintain a secure usage of eval in that scenario as opposed to using some other design pattern for dynamic transition application? Most of the time keeping in the back of your mind that everything you do with that eval needs to pass a set of checks to remain secure is not worth using it in anything other than trivial scenarios. Good questions, though.

    Your question about "only available to administrators" is exactly where you need to change your thinking. Reflected XSS is used for this exact situation. I'm logged in as administrator to example.com. Someone sends me a link in an email like www.example.com?abc=some_malicious_javascript and like a fool I click it. If the abc parameter is vulnerable, then this attack will work. You must ensure your use of eval() is defended from this type of attack.

License under CC-BY-SA with attribution


Content dated before 7/24/2021 11:53 AM