robert-j-webb/stackedit

robert-j-webb/stackedit

“Eval is only one letter away from evil.”

— Js developers

“Do not ever use eval!”

— MDN page on eval

Eval is the universally shunned function of the JS standard library. Folk programming logic tells us that any usage can be refactored away to code that doesn’t rely on it, and that it should never be used on a source that you don’t trust. Even if you somehow find a use case that works and you sanitize the user input, it’s said that by including eval in your code base, you will be encouraging future developers to use it for bad purposes. I’m going to attempt to refute these arguments by walking through my theoretical implementation of Safe Eval.

Introducing Safe Eval

Safe eval is a wrapper around eval where only certain characters are allowed to be executed and the rest are thrown away. It’s designed to only permit pure, no side effect algorithms that have to halt as well as no XSS. These characters are:

[?:] [0-9.()] [+-/*] [><=!&|]

Let’s evaluate what’s allowed with this set of characters:

[?:] Ternary expressions

By using expressions like 8 + 5 > 3 ? 5 : 3, you can replicate almost any algorithm without iteration or recursion in it.

[0-9 . ([^s]+) +-/*] Arithmetic

0-9 and arithmetic operators allow us to create constants and apply arithmetic operations on them. The [^s]+ means there needs to be at least one non-whitespace character in-between the parenthesis to avoid function calls.

[><=!&|] Boolean Expressions

By using <=, <, >, >=, ===, ==!, &&, ||, we can evaluate any boolean expressions.

Let’s evaluate what this can’t do:

  1. Call any function! It’s impossible to do so. Although you can construct a regex with this set of characters, you can’t access properties on the regex with just numbers. Additionally, (() => 5)() doesn't work because we don't allow open and close parens next to each other.
  2. Modify any variables! There’s no way to get an identifier with this set of characters. In other words, no variable name can be made.
  3. Loop infinitely! There’s no way to recurse, while, or any such thing. This formula is guaranteed to halt. It’s possible to make a formula that will take a very long time to evaluate, but that’s it! You could also set a maxlength on the formula, so as to make this very difficult. I would love to see what short character equations are possible with this set that take more than a few milliseconds to evaluate.
  4. Make a string, object, or array. Unfortunately, by allowing quotes, square brackets, or curly brackets, you can most likely write any code that you want at this point. See jsfuck for example.

So Safe Eval is safe! You can confidently run code from users by restricting their JS to a small, pure, mathematical instruction set.

You might be thinking at this point:

"Well great, I guess it’s somewhat safe to run eval on a purely mathematical expression. But why would I want to do that? There is no input to the expression, so why not just serve up the result? Why calculate a formula on the client at all?"

Your correct. Arithmetic eval is the second step of the function I’m proposing. The first step is providing variables into the formula via interpolation.

"Why would you ever want that! Ths use case for that must be contrived."

A valid use case for Interpolation into Safe Eval:

User Marsha is customizing their shop for their hard earned neopets loot. They want to encourage loyalty, so they want to have a discount if a customer is a repeat buyer. She selects "add a dynamic discount" from the shop edit screen and she is greeted with a form like this one:

Create a Discount
Variables ( price, numberPreviousItemsPurchased, affinityForCats, isActuallyARobot
Formula (

Read More