Dynamic evaluation runs code held in memory rather than code loaded from a source file. In JavaScript, eval() turns a string into executable code. That capability becomes dangerous when the string originates with an HTTP request: an attacker may turn application input into instructions for the web server. section 12.1
const express = require('express')
const app = express()
app.use(express.json())
app.post('/execute-command', (req, res) => {
const result = eval(command)
res.json({ result })
})
This endpoint illustrates the red flag: evaluating a command received by a web application gives an attacker a path to arbitrary code execution in the server runtime. section 12.1
The resulting attack is remote code execution (RCE). Malicious code running in the server runtime can explore filesystem contents or contribute to a full system takeover. Obvious eval() calls should raise concerns in review, but real RCE flaws often arise through subtler paths where input eventually reaches a dynamic execution feature. section 12.1
Treat dynamic evaluation as a security boundary:
- Never execute untrusted HTTP-request input as code. section 12.1
- Review code paths that transform strings or user-controlled expressions into executable server-side instructions. section 12.1
- Avoid using the host language's dynamic evaluator as the easy implementation for a web-facing expression language. section 12.2
A common temptation appears when an application offers a domain-specific language (DSL), such as search operators or spreadsheet-style formulas. DSLs commonly accept single-line expressions, and dynamically evaluating those expressions in the server language is easy—but generally the wrong design. Without a strong grasp of sandboxing, it can allow RCE vulnerabilities to creep in. section 12.2
Evaluate a DSL without exposing the host runtime
One option is an embedded scripting language such as Lua. The application can explicitly control which host-language objects, if any, are passed to the Lua runtime during evaluation. Another option is to formally define the DSL syntax, tokenize expressions through lexical analysis, then parse and evaluate only the operations the DSL permits. section 12.2 section 12.2
import lupa
lua = lupa.LuaRuntime(
unpack_returned_tuples=True) #1
expression = "2 + 3" #2
result = lua.execute(expression) #3
The Lua example evaluates a simple expression in an embedded runtime, illustrating a separate evaluation environment for application-defined expressions. section 12.2
The practical rule is simple: code-like input is not harmless merely because it is stored in a string. Keep untrusted input out of dynamic evaluators, and design expression features around restricted runtimes or explicitly parsed syntax instead of unrestricted host-language execution. section 12.1 section 12.2
