Destructuring Tweets - Episode 7 - Even more Evil Eval
Tags: snippet, javascript, destructuring, eval
Published: 2021-02-14 19:36:33

---
title: Destructuring Tweets - Episode 7 - Even more Evil Eval
published: true
description: I pick a more or less random snippet from Twitter and analyze it in depth in this series. It shall help me, and you understand the trickery behind it. This episode features insights about the feature you shouldn't use: eval.
tags: snippet, javascript, destructuring, eval 
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/ldtsttjfleqspakiey52.png
---

Grüß dich! Welcome to the series about destructuring a JavaScript quiz from Twitter. This Sunday, you'll learn about the *one* API you should never use: eval.[^1]

# Snippet of the Week

This week's [snippet](https://twitter.com/h43z/status/1356614035706380288) is from [h43z](https://twitter.com/h43z):
```javascript
function challenge(input){
  eval(input.toUpperCase())
}

// provide an input that makes function challenge call alert(1)
challenge('alert(1)');
```
Here we move into muddy waters. The author declares a function called `challenge`, which wraps `eval`. The trick is that the argument of the wrapper-function gets piped through `.toUpperCase()` first. 
The exercise is to make the function execute `alert(1)`.

# The Output

The output here is not spectacular but feels kind of magic if you do not know what `eval` exactly does. However, it is reasonably straightforward: `eval` executes whatever piece of code gets passed as a string.
So, for our snippet, the interpreter throws an error since `eval` goes and tries to execute "ALERT", which is undefined in the global scope.

```
ReferenceError: ALERT is not defined 
```

# The Analysis

So, first things first, let's go back to the snippet and examine what exactly happens there. We pass on the argument `alert(1)`. In case we would not have a wrapper function,  this piece of code would execute an `alert` just fine:
```javascript
eval('alert(1)');
```
However, since it gets piped through `.toUpperCase()`, the string, thus the called function, is actually `ALERT`, and JavaScript is a case-sensitive language!
Now we need to overcome this issue. I came up with three possible solutions. Let's check them one by one.

## Altering the Prototype of String

Since the method `toUpperCase` is part of the `String` prototype, we can easily alter its function body:
```javascript
function challenge(input){
  eval(input.toUpperCase())
}

String.prototype.toUpperCase = () => alert(1);
challenge('alert(1)');
```
In that case, when `toUpperCase` gets called on `input`, it does not pipe and parse the string but instead executes an alert. The called function is just overwritten with the target behavior.

## Adding the function ALERT

We can also go the other way around and add the missing function `ALERT` to the global object. 
```javascript
function challenge(input){
  eval(input.toUpperCase())
}

window.ALERT = input => alert(input);
challenge('alert(1)');
```
That approach is straight forward. We add another function with the right name. Instead of calling `alert`, we call `ALERT` instead, which then passes its argument on to `alert`.

## Passing an Object

The first two solutions were actually illegal. The author explicitly stated to solve the challenge by just passing an input. This is what we do in that approach. We pass an object with the function `toUpperCase`.
```javascript
function challenge(input){
  eval(input.toUpperCase())
}

challenge({ toUpperCase: () => 'alert(1)' });
```
Instead of using the implementation in String's prototype, we pass an object with its own version of `toUpperCase`.

# Snippet Summary

- **Trickery**: how to manipulate an existing function call
- **Key Learning**: JavaScript is case-sensitive, `eval` executes code from a string (and shouldn't be used!), prototyping & global scope
- **Further Reading**:
    - [Eval](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval)
    - [String Prototype toUpperCase](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase)
    - [JavaScript's case-sensitivity](https://sebhastian.com/is-javascript-case-sensitive/)
    - [The Window Object](https://developer.mozilla.org/en-US/docs/Web/API/Window/window)
    - [Prototypes](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes)

[^1]: **Warning**: Executing JavaScript from a string is an enormous security risk. It is far too easy for a bad actor to run arbitrary code when you use eval(). Read more at [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#never_use_eval!)