The dangerous world of Javascript’s eval() and encoded strings.

Eric Lum
Eric Lum
Feb 1, 2018 · 3 min read

In Javascript, eval() is one of the most interesting yet most dangerous functions in the language. Eval() takes a string and attempts to run it as Javascript code.

eval("console.log('hello world')") // hello world

While the above example is safe and trivial, there are some dangerous security implications of being able to execute Javascript code as string.

History and uses of eval()

Eval has existed since the first ECMA specification published in June 1997. It is specified by the following on page 32 of the spec:

Eval code is the source text supplied to the built-in eval function. More precisely, if the parameter to the built-in eval function is a string, it is treated as an ECMAScript Program. The eval code for a particular invocation of eval is the global code portion of the string parameter. — ECMA 262, 1st Edition, June 1997

Eval() is an instance of a meta-circular evaluator, or a language interpreter that can be used within itself. Many other programming languages contain an eval-like function, including Ruby, Python, and Perl.

While often misused, it can be useful for allowing generated code to run at a given point. While under controlled conditions, this is not a major issue, the general consensus amongst the Javascript community is that you should rarely if ever use it. Here’s a list of applications in which you must use eval():

  1. Running code remotely sent from a server
  2. Evaluating user input code**
  3. Running dynamically generated code
  4. Running a script and storing its result

While applications 1,3, and 4 are generally safe, there are real security concerns to our second application — evaluating user input code.

Cross site scripting (XSS) and sanitized inputs

XSS Attacks

Running user input code can be a dangerous move since it can affect the internal state of an application. For example, imagine we had a web app with a text field input that we were running eval() on. An attacker could easily run a script into your input field in order to perform a DOM Based XSS (cross site scripting) attack. This is an attack where malicious code is used to make the client-side DOM behave in an unexpected way, and therefore executes code differently within a user’s browser. This can be a route to render a malicious form into the page or redirect the user.

While all modern browsers allow the use of JSON.parse(), many legacy browsers do not, and force you to use the Javascript eval() as a method of creating a JSON object. This can be exploited in a similar fashion to perform a server-side XSS attack

Sanitizing Inputs

In order to prevent XSS attacks from running malicious code, developers should provide checks to their inputs before running eval(). Developers often use keyword blacklists and whitelists that will not allow certain keywords to be sent in as input or only allow certain keywords as input respectively. While this can prevent many attacks, there are other more refined and odd looking attacks that may not be as predictable. As you will see, sanitizing inputs can be difficult due to some other delightful features of Javascript.

Goofy Strings and code obfuscation

Consider the following code snippet:

$=~[];$={___:++$,$$$$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$$:({}+"")[$],$$_$:($[$]+"")[$],_$$:++$,$$$_:(!""+"")[$],$__:++$,$_$:++$,$$__:({}+"")[$],$$_:++$,$$$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$$=($.$+"")[$.__$])+((!$)+"")[$._$$]+($.__=$.$_[$.$$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$$=$.$+(!""+"")[$._$$]+$.__+$._+$.$+$.$$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$$+"\""+(![]+"")[$._$_]+$.$$$_+$.__+"\\"+$.$__+$.___+$.$_$_+"\\"+$.__$+$.$$_+$._$_+"\\"+$.__$+$.$$_+$._$_+$.$_$_+"\\"+$.__$+$.$$$+$.__$+"\\"+$.$__+$.___+"=\\"+$.$__+$.___+"[]\\"+$.__$+$._$_+$.$_$_+"\\"+$.__$+$.$$_+$._$_+"\\"+$.__$+$.$$_+$._$_+$.$_$_+"\\"+$.__$+$.$$$+$.__$+".\\"+$.__$+$.$$_+$.___+$._+"\\"+$.__$+$.$$_+$._$$+"\\"+$.__$+$.$_$+$.___+"("+$.__$+")\\"+$.__$+$._$_+$.$$__+$._$+"\\"+$.__$+$.$_$+$.$$_+"\\"+$.__$+$.$$_+$._$$+$._$+(![]+"")[$._$_]+$.$$$_+"."+(![]+"")[$._$_]+$._$+"\\"+$.__$+$.$__+$.$$$+"("+$.$_$_+"\\"+$.__$+$.$$_+$._$_+"\\"+$.__$+$.$$_+$._$_+$.$_$_+"\\"+$.__$+$.$$$+$.__$+")"+"\"")())();

The above is an encoded string of characters that javascript will evaluate as the below translation(courtesy of jjencode).

let array = []
array.push(1)
console.log(array)

You might wonder how your browser console can even run this string of odd punctuation, but recall that Javascript is a weakly-typed language that will bend over backwards in order to evaluate any code you give it. Sometimes with some comical consequences.

There are some interesting examples of this in other ‘ridiculous’ looking javascript, including JSF*ck, notably made of a set of only 6 characters: (, ), [, ], !, +. Using encoded strings like the above can make input sanitization a near impossible task, making them prime vectors for XSS attacks.

Summary

While eval has been a historic part of Javascript, it generally should not be used unless in very specific and secured applications. Considering Javascript’s position as the language of the web, it’s weakly-typed properties can make it into a powerful and abusable tool for malicious attacks and hacks on the web applications.

Eric Lum

Written by

Eric Lum

Software Engineer, amateur chef, really amateur ios photographer, aspiring part time model

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade