<p>Many dynamic languages such as Javascript, PHP and Python have a built-in <code>eval</code> function for executing code from a string. It's well known that such functions are dangerous because arbitrary things could go wrong if untrusted user input makes its way into the string that gets executed. Malicious code could modify the program state or perform other unwanted side-effects; attempt to allocate all of the available memory; overflow the stack; or loop infinitely.</p>
<p>However, despite their danger, programmers still use <code>eval</code> functions for convenience, and there are some niche uses (e.g. automated grading of programming assignments) where executing untrusted code is inherent to the task. So:</p>
<ul>
<li>For languages which do have a safe <code>eval</code> function, how is that safety ensured by the design of the language and/or the <code>eval</code> function's API?</li>
<li>Or otherwise, what work has been done to identify how a language with a safe <code>eval</code> function could be designed?</li>
</ul>
<p>To be clear, this question is not about OS-level mitigations (e.g. running untrusted code in a separate process as an unprivileged user), and not about about the implementation (e.g. how to algorithmically check whether some input code could perform a banned operation). I'm asking about how <code>eval</code> could be made safe <em>by design</em>, either in existing languages or in prior work attempting this.</p>

<standard-library>
How do languages support executing untrusted user code at runtime?
CC BY-SA 4.0
2023-09-01T18:47:11.620Z
Web browsers are facing this problem: running untrusted JavaScript or WebAssembly code that must be contained. The sandboxing is as much a property of the runtime system as the language. JavaScript implements eval, after all.
Christian Lindig
CC BY-SA 4.0
2023-09-01T18:56:53.010Z
Sandboxing has been a perennial problem that has been difficult to solve. This is what doomed Java in browsers, and Flash had similar problems. JavaScript has been successful because they started from a base with no access to external resources, and added features incrementally, always being cognizant of the need to limit access to the host environment in browsers.
Barmar
CC BY-SA 4.0
2023-09-01T19:14:07.147Z
@ChristianLindig I would say that web browsers aren't an example of this, because the browsers themselves aren't written in Javascript and don't invoke `eval` to run Javascript on loaded pages.
kaya3
CC BY-SA 4.0
2023-09-01T19:15:18.770Z
You have to define a threat model and add the necessary checks to protect your code against it: do you want to limit its size, the memory it can allocate, the files it can open, etc., With a good use of packages/modules/namespaces you can prepare an environment where the user has no path to access critical functions. You can put timeout.
coredump
CC BY-SA 4.0
2023-09-01T19:23:50.880Z
Maybe an example for some success in taming the problem: PostScript is a programming language that has general control structures; PDF is derived from PostScript but does not have control structures – so its execution is always guaranteed to terminate.
Christian Lindig
CC BY-SA 4.0
2023-09-03T19:29:20.350Z
@kaya3 *"browsers...don't invoke eval to run Javascript on loaded pages."* What difference would eval make? All `eval(code)` does is run the interpreter on `code`, and `<script>code</script>` does *exactly* the same thing. Every web page you visit can *already* run arbitrary untrusted code on your system unless you have Javascript turned off.
Ray
CC BY-SA 4.0
2023-09-03T19:38:18.580Z
@Ray The difference is that `eval` runs code as a string from within other Javascript code. If browsers used `eval` to run Javascript code on webpages, then that code would have access to whatever variables were in scope in the browser's source code. `eval` doesn't "only" invoke the interpreter on the code provided, it also passes context from the caller and returns a value back to the caller.
kaya3
CC BY-SA 4.0
2023-09-04T12:09:07.227Z
Define "safe" please! Also be aware even without using equivalents of `eval` there is no guarantee that the program code is "safe" (whatever that means).
U. Windl
CC BY-SA 4.0
2023-09-04T16:53:43.910Z
@U.Windl Safety is defined in the question with reference to these dangers: *"Malicious code could modify the program state or perform other unwanted side-effects; attempt to allocate all of the available memory; overflow the stack; or loop infinitely."*
kaya3
CC BY-SA 4.0
2023-09-05T07:54:00.933Z
@kaya3 Actually those were examples of what "bad evals" could do, but not really a definition of "safe". As in general no program can find out what another program does (the halting problem), I think it was valid to ask what "safe" should be.
U. Windl
CC BY-SA 4.0
2023-09-05T16:51:17.017Z
@U.Windl I didn't say it was invalid to ask. I said that's the answer to your question: safety here means preventing those things from happening.
kaya3
<p>Without a clear threat model, this is borderline too broad, but there are several attested approaches that attempt to provide some general level of safety. It's also worth noting here that most of the issues of <code>eval</code> are exactly those of dynamic loading of code in general, so systems that give protection there also address string evaluation. A limitation in terms of real-world examples is that <code>eval</code> is so deeply deprecated that languages that care simply don't have it — but they often do have dynamic loading.</p>
<h1>Object Capabilities</h1>
<p>The <a href="https://en.wikipedia.org/wiki/Object-capability_model" rel="noreferrer">object-capability model</a>, in short, is that holding a reference to an object indicates that you have permission to access all of its operations, and so operations that are not universally available can be encapsulated within an object. That object can be guarded carefully, and when access to <em>some</em> of the protected actions should be given, a wrapper object exposing only those operations can be created and given to other code.</p>
<p>A language based around this approach will not expose any access to the outside world other than through an initial global capability, which can be refined to restrict the access of <em>any</em> code, not only <code>eval</code>ed code, including both dynamically-loaded code and code written within the program itself. Whenever code is executed it must be provided the capability or capabilities it will be permitted to use — possibly as ordinary arguments, or possibly through a capability-specific mechanism of the language — and it's certain that that code can't do anything beyond those, and can't trick <em>other</em> functions into doing those tasks because it would need to provide that function a valid capability to allow that.</p>
<p>Notable languages following this model include Emerald, Joule, E, Newspeak, and Wyvern. Google's Caja system for JavaScript also used it. It's an active area of research. It's possible to build implementations of this system on top of most OO languages, but if the language itself provides escape hatches (e.g. language <em>keywords</em> for file access, loading other code, and so on) then it has limited effect.</p>
<p>Despite the name, this doesn't strictly need to be in an object-oriented language: an opaque token that is passed around and tracked by the runtime can provide exactly the same facility, though defining restricted subcapabilities just by creating objects using the ordinary features of the language is a major convenience. The broader area of <em>capability-based security</em> encompasses all approaches here.</p>
<h1>Privilege dropping</h1>
<p>Another quite-related model is to allow the program to drop certain abilities at will, without providing the ability to transfer them around. This is broadly aligned with what POSIX calls &quot;capabilities&quot; (which are different to the object-capability model and general capability-based security), but at the linguistic level. The program can choose to drop the ability to open files, for example, either permanently or for the dynamic duration of a particular function or block. If code is <code>eval</code>ed during that time, it won't be able to do that either.</p>
<p>This is in essence what the <a href="https://docs.oracle.com/javase/tutorial/essential/environment/security.html" rel="noreferrer">Java Security Manager</a> was giving, and was part of the original proposition for Java. It has some significant limitations, particularly that it is a negative instead of affirmative system: it's not resilient against <em>new</em> privileges being added in the broader system.</p>
<h1>Environment provision</h1>
<p>Many languages' <code>eval</code> allows providing a scope in which to execute the code. This scope can contain variables to be read or modified, and often definitions of functions as well. Python <a href="https://docs.python.org/3/library/functions.html#eval" rel="noreferrer">is one such language</a>: passing in a dictionary of globals and/or locals restricts access to the true values, and can shim standard functions. This is a core pattern in Lisp, and Tcl <a href="https://www.tcl-lang.org/man/tcl8.4/TclCmd/safe.htm" rel="noreferrer">is another</a> that provides fine-grained ability to control the evaluation environment.</p>
<h1>Purity</h1>
<p>A pure functional language inherently exposes no unfettered access to the outside world, and so evaluating untrusted code is &quot;safe&quot; from those impacts. However, infinite recursion or repetition may still be possible. There are pure functional languages that provide this (even <a href="https://hackage.haskell.org/package/plugins-1.6.2.1/docs/System-Eval-Haskell.html" rel="noreferrer">Haskell can, via dynamic loading</a>), though they are not very common.</p>
<h2>Totality</h2>
<p>To avoid the runaway-repetition scenario, a language can enforce that all valid code be total and provably terminate. Agda is such a language. These languages <em>could</em> provide <code>eval</code> safely, although I can't find any that do, probably because it's so clearly a bad idea.</p>
<h1>Static effect systems</h1>
<p>An <a href="https://en.wikipedia.org/wiki/Effect_system" rel="noreferrer">effect system</a>, broadly, identifies the computational effects of code: what side effects can occur, and where. These propagate, such that code that has effect X (such as writing to a file) contaminates any code that calls it with the same effect, unless somehow suppressed by a language construct. A familiar (limited) example of an effect is Java's checked exceptions, but other common effects modelled are file and network access (sometimes including <em>specific resources</em>), memory mutation, and control flow.</p>
<p>A language exposing a two-step <code>eval</code> process can leverage this: parse and process the code into an unexecuted value, which is annotated with its effects. Client code can then examine the value and determine whether to run it or not based on the effects determined. Execution can even be prohibited at the language level when the &quot;execute&quot; operation has correct effect annotations.</p>
<p>I'm not aware of a language that does this specifically for <code>eval</code>, but it is part of the dynamic loading system of <a href="https://www.unison-lang.org/" rel="noreferrer">Unison</a>, and arguably of Java in the case of exceptions.</p>
<h1>Domain-specific languages</h1>
<p>Rather than exposing evaluation of the <em>same</em> language as the host, a more limited language can be exposed for the cases where evaluating user code is required. These sublanguages can then have requirements of totality, purity, and so on that are not imposed on the host language. This is in effect what the <a href="https://github.com/google/cel-spec" rel="noreferrer">Common Expression Language</a> is to Go, although it is formally an external library. Python provides <a href="https://docs.python.org/3/library/ast.html#ast.literal_eval" rel="noreferrer"><code>ast.literal_eval</code></a> for interpretation of literals only (but not expressions on them).</p>
<p>A restricted <code>eval</code> reusing only expression-oriented parts of the language's parser and running on provided data is a fairly cheap extension to an interpreter. Strictly speaking, this is also what many languages' regular-expression systems are, although they are not usually computationally useful in that way.</p>
<h1>Operating-system-level isolation</h1>
<p>You wanted to rule this out of scope, but overall &quot;safety&quot; inherently can't be guaranteed purely at the level of the language runtime. Process isolation is one strong boundary against escapes through implementation bugs, but OS-level capability systems with linguistic support (as in <a href="https://joeduffyblog.com/2015/11/10/objects-as-secure-capabilities/" rel="noreferrer">Midori</a>) also help. How much this is necessary or helpful depends on the threat model involved.</p>
<h1>Sandboxing and timeouts</h1>
<p>The original proposition of Java was that it would be safe to run untrusted code within other systems due to sandboxing. It didn't work out as well as intended, but this is a valid approach in combination with other methods. The most straightforward approach to preventing nontermination is simply to impose a time limit, either at the system level or linguistically. These are the obvious approaches that aren't worth more detail, but they are a realistic part of any practical system.</p>
<h1>Nothing</h1>
<p>In practice, this is overwhelmingly the most common option. Languages that add <code>eval</code> itself today mostly don't care about these issues: they treat it as the programmer's responsibility to be safe and tell them they shouldn't use it.</p>
<h1>Expose alternatives for <em>common</em> cases</h1>
<p><a href="https://doi.org/10.1007/978-3-642-22655-7_4" rel="noreferrer">Richards et al.</a> found in 2011 that the principal uses of <code>eval</code> in JavaScript code were for dynamically accessing language facilities like field access or assignment, or for JSON parsing. Many of these were either mistakes or design flaws in the code, such as faking an array with a sequence of variables <code>eval(&quot;subPointArr_&quot; + i)</code>, or evaluating a field access instead of using <code>[]</code> indexing.</p>
<p>A number of uses were for tasks that the standard library or ecosystem now provide inbuilt and safe methods for, like JSON parsing and deferred loading of scripts. Many uses were function calls with dynamic argument lists, which <em>were</em> possible at the time without <code>eval</code>, but awkwardly (via Function.prototype.apply), and are now exposed as a language feature using spread syntax.</p>
<p>A very large proportion of the uses of <code>eval</code> found are thus no longer necessary (or weren't ever). The safest <code>eval</code> is the one that doesn't happen, so it may be that the best way to make <code>eval</code> safe is to eliminate the cases that require it, and then remove the functionality itself. This is probably the best <em>language-design</em> pathway if aspiring for safety.</p>
<p><sub>Richards, G., Hammer, C., Burg, B., Vitek, J. (2011). The Eval That Men Do. In: Mezini, M. (eds) ECOOP 2011 – Object-Oriented Programming. ECOOP 2011. Lecture Notes in Computer Science, vol 6813. Springer, Berlin, Heidelberg. <a href="https://doi.org/10.1007/978-3-642-22655-7_4" rel="noreferrer">https://doi.org/10.1007/978-3-642-22655-7_4</a></sub></p>

CC BY-SA 4.0
2023-09-01T21:59:52.573Z
2023-09-01T22:20:35.347Z
2023-09-01T22:20:35.347Z
Michael Homer
CC BY-SA 4.0
2023-09-01T22:17:52.220Z
Re: *"overall "safety" inherently can't be guaranteed purely at the level of the language runtime"*, I get your point about possible implementation bugs, but from the perspective of language design, all safety guarantees (e.g. memory safety) are subject to the language being correctly implemented; and it's not normally argued that memory safety is impossible at the language level. Although perhaps it can be argued that `eval` can't be made safe due to the relatively high likelihood of *design* mistakes.
kaya3
CC BY-SA 4.0
2023-09-01T22:24:15.370Z
Yes, you can't guard against implementation mistakes perfectly, but any time that you have untrusted iteration/recursion/memory changes the practical attack surface gets *very* large very quickly because any bug can be prodded to produce an outcome — consider all the security issues that have arisen just from the tiny bit of executable code in fonts.
Michael Homer
CC BY-SA 4.0
2023-09-02T18:14:23.467Z
Unfortunately, while it would be possible for a C implementation to support static determination of effects for most actions, the __STDC_ANALYZABLE spec is too vague to e.g. distinguish implementations where integer computations other than divie/remainder never have side effects beyond yielding possibly meaningless values, those where side-effect-free loops may be skipped or prevent execution of subsequent code, but can't have other arbitrary side effects.
supercat
CC BY-SA 4.0
2023-09-02T19:36:24.573Z
How would you implement something like Vue.js without `eval` (or other things like `new Function`)?
xigoi
CC BY-SA 4.0
2023-09-02T20:19:55.100Z
@xigoi You can preprocess all the embedded code out of Vue pages into actual script blocks & functions if you want to, but certainly there will be systems that make use of `eval` now that wouldn't be able to if it didn't exist and would need to have followed a different approach.
Michael Homer
CC BY-SA 4.0
2023-09-03T16:37:17.397Z
@xigoi: In practice, object-capability languages have `eval`; I have hacked on a variant of E, and `eval` was implemented in high-level code as a library.
Corbin
<h2>Safe TCL</h2>
<p>TCL supports this as <a href="https://www.tcl.tk/software/plugin/safetcl.html" rel="noreferrer">safe TCL</a></p>
<p>In TCL all control structures are implemented as commands and any command can be replaced.</p>
<p>In TCL you can create a new interpreter from within TCL itself which only supports the safe subset.</p>
<p>Here is a <a href="https://www.usenix.org/publications/library/proceedings/usenix98/full_papers/levy/levy.pdf" rel="noreferrer">paper</a> from 1998 that describes this in some detail.</p>
<h2>Other Approaches</h2>
<p>The basic approach there is to create a restricted more secure subset of your base language.</p>
<p>You could also consider:</p>
<ul>
<li><p><a href="https://en.wikipedia.org/wiki/Capability-based_security" rel="noreferrer">A capabilities model</a></p>
</li>
<li><p>Limiting usage of resources (memory, threads, files etc.)</p>
</li>
<li><p><a href="https://en.wikipedia.org/wiki/Runtime_verification" rel="noreferrer">Runtime_verification</a></p>
</li>
<li><p><a href="https://en.wikipedia.org/wiki/Provable_security" rel="noreferrer">Provable_security</a></p>
</li>
</ul>
<p>These improve on devising a safe subset by adding compile and/or run time checks that the untrusted code is safe for some measure of safe.</p>
<h2>Consider other Sandboxing Approaches</h2>
<p>There is an interesting discussion for the case of python here:</p>
<p><a href="https://stackoverflow.com/questions/3688708/python-safe-sandbox">https://stackoverflow.com/questions/3688708/python-safe-sandbox</a></p>
<h2>Maybe <code>eval</code> is too general?</h2>
<p>Eval is often much more general that you require.
For example in the case of attacks like <a href="https://en.wikipedia.org/wiki/SQL_injection" rel="noreferrer">SQL injection</a> maybe you don't need to be able to execute an arbitrary query maybe its enough to specify a table and key.</p>
<p>An example of similar kind of injection attack can occur if you delegate to something via text like</p>
<pre><code> doSomething --parseString $SomeStringInFormatX
</code></pre>
<p>In this case you could possibly attack via something like:</p>
<pre><code> &quot;parseThis --acommand line option ;a new command altogether&quot;
</code></pre>
<p>Using -- to start another command line option or ; to start a new command if doSomething is evaluated directly.
Whereas if the code to be parsed is in a file the attack surface is limited to the capabilities allowed when parsing a file of type X.</p>
<p>So you could instead say:</p>
<pre><code> doSomething --parseFile $SomeFileInFormatX
</code></pre>
<p>Or better skip the text altogether and have a function:</p>
<pre><code> doSomething(SomeFileNameInFormatX: path)
</code></pre>
<hr />
<p>I should add that many of these approaches have risks. In TCL, for example, you can add commands to the inner interpreter and make it unsafe.
Also I don't know know if there is any proof that the &quot;safe&quot; subset cannot be circumvented.</p>
<p>The only surefire way to secure untrusted code would be running proofs on untrusted code and that is a hard problem.</p>
<p>Look for references like for example - <a href="https://www.cylab.cmu.edu/news/2022/10/11-provably-safe-sandboxing.html" rel="noreferrer">https://www.cylab.cmu.edu/news/2022/10/11-provably-safe-sandboxing.html</a></p>
<hr />
<p>Also you mention making <code>eval</code> safe by design and specifically not considering OS-level mitigations but you simply cannot ignore those.</p>
<p>For example, if you allow memory allocation than you will have to provide a way limit it as a function of your runtime or you allow a attack that will exhaust your memory. Sometimes the OS can help you there. For example, with posix and linux you can set resource limits. If the OS doesn't go far enough you will have to add similar things to your runtime. The more you do that the more your runtime will begin to ressemble an OS in some aspects.
It is a perfectly valid approach to say I don't want to have to worry too much about that and instead use external sandboxing solutions be they OS sandboxes, containers (docker etc), unikernals or virtualisation. As an added bonus you can potentially 'trust' systems that aren't part of your language at all. Using docker to implement 'eval' might be a bit of a sledgehammer but that sledgehamemr is a useful tool in its own right.</p>

CC BY-SA 4.0
2023-09-01T19:36:57.297Z
2023-09-02T10:20:42.353Z
2023-09-02T10:20:42.353Z
Bruce Adams
CC BY-SA 4.0
2023-09-01T19:40:52.893Z
I would be interested to hear about examples (assuming they exist) where safeTCL has been defeated other than by a careless choice of commands being added to the inner interpreter and also about similar approaches in other languages.
Bruce Adams
# How do languages support executing untrusted user code at runtime?
Posted by: username_0 on 2023-09-01
Many dynamic languages such as Javascript, PHP and Python have a built-in `eval` function for executing code from a string. It's well known that such functions are dangerous because arbitrary things could go wrong if untrusted user input makes its way into the string that gets executed. Malicious code could modify the program state or perform other unwanted side-effects; attempt to allocate all of the available memory; overflow the stack; or loop infinitely.

However, despite their danger, programmers still use `eval` functions for convenience, and there are some niche uses (e.g. automated grading of programming assignments) where executing untrusted code is inherent to the task. So:

* For languages which do have a safe `eval` function, how is that safety ensured by the design of the language and/or the `eval` function's API?
* Or otherwise, what work has been done to identify how a language with a safe `eval` function could be designed?

To be clear, this question is not about OS-level mitigations (e.g. running untrusted code in a separate process as an unprivileged user), and not about about the implementation (e.g. how to algorithmically check whether some input code could perform a banned operation). I'm asking about how `eval` could be made safe *by design*, either in existing languages or in prior work attempting this.
**Tags:** standard-library
> **Comments:**
> **username_1**: Web browsers are facing this problem: running untrusted JavaScript or WebAssembly code that must be contained. The sandboxing is as much a property of the runtime system as the language. JavaScript implements eval, after all.  
> **username_2**: Sandboxing has been a perennial problem that has been difficult to solve. This is what doomed Java in browsers, and Flash had similar problems. JavaScript has been successful because they started from a base with no access to external resources, and added features incrementally, always being cognizant of the need to limit access to the host environment in browsers.  
> **username_0**: @ChristianLindig I would say that web browsers aren't an example of this, because the browsers themselves aren't written in Javascript and don't invoke `eval` to run Javascript on loaded pages.  
> **username_3**: You have to define a threat model and add the necessary checks to protect your code against it: do you want to limit its size, the memory it can allocate, the files it can open, etc., With a good use of packages/modules/namespaces you can prepare an environment where the user has no path to access critical functions. You can put timeout.  
> **username_1**: Maybe an example for some success in taming the problem: PostScript is a programming language that has general control structures; PDF is derived from PostScript but does not have control structures – so its execution is always guaranteed to terminate.  
> **username_4**: @kaya3 *"browsers...don't invoke eval to run Javascript on loaded pages."* What difference would eval make? All `eval(code)` does is run the interpreter on `code`, and `<script>code</script>` does *exactly* the same thing. Every web page you visit can *already* run arbitrary untrusted code on your system unless you have Javascript turned off.  
> **username_0**: @Ray The difference is that `eval` runs code as a string from within other Javascript code. If browsers used `eval` to run Javascript code on webpages, then that code would have access to whatever variables were in scope in the browser's source code. `eval` doesn't "only" invoke the interpreter on the code provided, it also passes context from the caller and returns a value back to the caller.  
> **username_5**: Define "safe" please! Also be aware even without using equivalents of `eval` there is no guarantee that the program code is "safe" (whatever that means).  
> **username_0**: @U.Windl Safety is defined in the question with reference to these dangers: *"Malicious code could modify the program state or perform other unwanted side-effects; attempt to allocate all of the available memory; overflow the stack; or loop infinitely."*  
> **username_5**: @kaya3 Actually those were examples of what "bad evals" could do, but not really a definition of "safe". As in general no program can find out what another program does (the halting problem), I think it was valid to ask what "safe" should be.  
> **username_0**: @U.Windl I didn't say it was invalid to ask. I said that's the answer to your question: safety here means preventing those things from happening.  
---
## 2 answers
### Answer by username_6 on 2023-09-01. Score: 22 | Accepted answer
Without a clear threat model, this is borderline too broad, but there are several attested approaches that attempt to provide some general level of safety. It's also worth noting here that most of the issues of `eval` are exactly those of dynamic loading of code in general, so systems that give protection there also address string evaluation. A limitation in terms of real-world examples is that `eval` is so deeply deprecated that languages that care simply don't have it — but they often do have dynamic loading.

# Object Capabilities

The [object-capability model](https://en.wikipedia.org/wiki/Object-capability_model), in short, is that holding a reference to an object indicates that you have permission to access all of its operations, and so operations that are not universally available can be encapsulated within an object. That object can be guarded carefully, and when access to *some* of the protected actions should be given, a wrapper object exposing only those operations can be created and given to other code.

A language based around this approach will not expose any access to the outside world other than through an initial global capability, which can be refined to restrict the access of *any* code, not only `eval`ed code, including both dynamically-loaded code and code written within the program itself. Whenever code is executed it must be provided the capability or capabilities it will be permitted to use — possibly as ordinary arguments, or possibly through a capability-specific mechanism of the language — and it's certain that that code can't do anything beyond those, and can't trick *other* functions into doing those tasks because it would need to provide that function a valid capability to allow that.

Notable languages following this model include Emerald, Joule, E, Newspeak, and Wyvern. Google's Caja system for JavaScript also used it. It's an active area of research. It's possible to build implementations of this system on top of most OO languages, but if the language itself provides escape hatches (e.g. language *keywords* for file access, loading other code, and so on) then it has limited effect.

Despite the name, this doesn't strictly need to be in an object-oriented language: an opaque token that is passed around and tracked by the runtime can provide exactly the same facility, though defining restricted subcapabilities just by creating objects using the ordinary features of the language is a major convenience. The broader area of *capability-based security* encompasses all approaches here.

# Privilege dropping

Another quite-related model is to allow the program to drop certain abilities at will, without providing the ability to transfer them around. This is broadly aligned with what POSIX calls "capabilities" (which are different to the object-capability model and general capability-based security), but at the linguistic level. The program can choose to drop the ability to open files, for example, either permanently or for the dynamic duration of a particular function or block. If code is `eval`ed during that time, it won't be able to do that either.

This is in essence what the [Java Security Manager](https://docs.oracle.com/javase/tutorial/essential/environment/security.html) was giving, and was part of the original proposition for Java. It has some significant limitations, particularly that it is a negative instead of affirmative system: it's not resilient against *new* privileges being added in the broader system.

# Environment provision

Many languages' `eval` allows providing a scope in which to execute the code. This scope can contain variables to be read or modified, and often definitions of functions as well. Python [is one such language](https://docs.python.org/3/library/functions.html#eval): passing in a dictionary of globals and/or locals restricts access to the true values, and can shim standard functions. This is a core pattern in Lisp, and Tcl [is another](https://www.tcl-lang.org/man/tcl8.4/TclCmd/safe.htm) that provides fine-grained ability to control the evaluation environment.

# Purity

A pure functional language inherently exposes no unfettered access to the outside world, and so evaluating untrusted code is "safe" from those impacts. However, infinite recursion or repetition may still be possible. There are pure functional languages that provide this (even [Haskell can, via dynamic loading](https://hackage.haskell.org/package/plugins-1.6.2.1/docs/System-Eval-Haskell.html)), though they are not very common.

## Totality

To avoid the runaway-repetition scenario, a language can enforce that all valid code be total and provably terminate. Agda is such a language. These languages *could* provide `eval` safely, although I can't find any that do, probably because it's so clearly a bad idea.

# Static effect systems

An [effect system](https://en.wikipedia.org/wiki/Effect_system), broadly, identifies the computational effects of code: what side effects can occur, and where. These propagate, such that code that has effect X (such as writing to a file) contaminates any code that calls it with the same effect, unless somehow suppressed by a language construct. A familiar (limited) example of an effect is Java's checked exceptions, but other common effects modelled are file and network access (sometimes including *specific resources*), memory mutation, and control flow.

A language exposing a two-step `eval` process can leverage this: parse and process the code into an unexecuted value, which is annotated with its effects. Client code can then examine the value and determine whether to run it or not based on the effects determined. Execution can even be prohibited at the language level when the "execute" operation has correct effect annotations.

I'm not aware of a language that does this specifically for `eval`, but it is part of the dynamic loading system of [Unison](https://www.unison-lang.org/), and arguably of Java in the case of exceptions.

# Domain-specific languages

Rather than exposing evaluation of the *same* language as the host, a more limited language can be exposed for the cases where evaluating user code is required. These sublanguages can then have requirements of totality, purity, and so on that are not imposed on the host language. This is in effect what the [Common Expression Language](https://github.com/google/cel-spec) is to Go, although it is formally an external library. Python provides [`ast.literal_eval`](https://docs.python.org/3/library/ast.html#ast.literal_eval) for interpretation of literals only (but not expressions on them).

A restricted `eval` reusing only expression-oriented parts of the language's parser and running on provided data is a fairly cheap extension to an interpreter. Strictly speaking, this is also what many languages' regular-expression systems are, although they are not usually computationally useful in that way.

# Operating-system-level isolation

You wanted to rule this out of scope, but overall "safety" inherently can't be guaranteed purely at the level of the language runtime. Process isolation is one strong boundary against escapes through implementation bugs, but OS-level capability systems with linguistic support (as in [Midori](https://joeduffyblog.com/2015/11/10/objects-as-secure-capabilities/)) also help. How much this is necessary or helpful depends on the threat model involved.

# Sandboxing and timeouts

The original proposition of Java was that it would be safe to run untrusted code within other systems due to sandboxing. It didn't work out as well as intended, but this is a valid approach in combination with other methods. The most straightforward approach to preventing nontermination is simply to impose a time limit, either at the system level or linguistically. These are the obvious approaches that aren't worth more detail, but they are a realistic part of any practical system.

# Nothing

In practice, this is overwhelmingly the most common option. Languages that add `eval` itself today mostly don't care about these issues: they treat it as the programmer's responsibility to be safe and tell them they shouldn't use it.

# Expose alternatives for *common* cases

[Richards et al.](https://doi.org/10.1007/978-3-642-22655-7_4) found in 2011 that the principal uses of `eval` in JavaScript code were for dynamically accessing language facilities like field access or assignment, or for JSON parsing. Many of these were either mistakes or design flaws in the code, such as faking an array with a sequence of variables `eval("subPointArr_" + i)`, or evaluating a field access instead of using `[]` indexing.

A number of uses were for tasks that the standard library or ecosystem now provide inbuilt and safe methods for, like JSON parsing and deferred loading of scripts. Many uses were function calls with dynamic argument lists, which *were* possible at the time without `eval`, but awkwardly (via Function.prototype.apply), and are now exposed as a language feature using spread syntax.

A very large proportion of the uses of `eval` found are thus no longer necessary (or weren't ever). The safest `eval` is the one that doesn't happen, so it may be that the best way to make `eval` safe is to eliminate the cases that require it, and then remove the functionality itself. This is probably the best *language-design* pathway if aspiring for safety.

Richards, G., Hammer, C., Burg, B., Vitek, J. (2011). The Eval That Men Do. In: Mezini, M. (eds) ECOOP 2011 – Object-Oriented Programming. ECOOP 2011. Lecture Notes in Computer Science, vol 6813. Springer, Berlin, Heidelberg. <https://doi.org/10.1007/978-3-642-22655-7_4>
> **Comments:**
> **username_0** (2023-09-01): Re: *"overall "safety" inherently can't be guaranteed purely at the level of the language runtime"*, I get your point about possible implementation bugs, but from the perspective of language design, all safety guarantees (e.g. memory safety) are subject to the language being correctly implemented; and it's not normally argued that memory safety is impossible at the language level. Although perhaps it can be argued that `eval` can't be made safe due to the relatively high likelihood of *design* mistakes.  
> **username_6** (2023-09-01): Yes, you can't guard against implementation mistakes perfectly, but any time that you have untrusted iteration/recursion/memory changes the practical attack surface gets *very* large very quickly because any bug can be prodded to produce an outcome — consider all the security issues that have arisen just from the tiny bit of executable code in fonts.  
> **username_7** (2023-09-02): Unfortunately, while it would be possible for a C implementation to support static determination of effects for most actions, the __STDC_ANALYZABLE spec is too vague to e.g. distinguish implementations where integer computations other than divie/remainder never have side effects beyond yielding possibly meaningless values, those where side-effect-free loops may be skipped or prevent execution of subsequent code, but can't have other arbitrary side effects.  
> **username_8** (2023-09-02): How would you implement something like Vue.js without `eval` (or other things like `new Function`)?  
> **username_6** (2023-09-02): @xigoi You can preprocess all the embedded code out of Vue pages into actual script blocks & functions if you want to, but certainly there will be systems that make use of `eval` now that wouldn't be able to if it didn't exist and would need to have followed a different approach.  
> **username_9** (2023-09-03): @xigoi: In practice, object-capability languages have `eval`; I have hacked on a variant of E, and `eval` was implemented in high-level code as a library.  
---
### Answer by username_10 on 2023-09-01. Score: 9
Safe TCL
TCL supports this as safe TCL
In TCL all control structures are implemented as commands and any command can be replaced.
In TCL you can create a new interpreter from within TCL itself which only supports the safe subset.
Here is a paper from 1998 that describes this in some detail.
Other Approaches
The basic approach there is to create a restricted more secure subset of your base language.
You could also consider:

A capabilities model

Limiting usage of resources (memory, threads, files etc.)

Runtime_verification

Provable_security


These improve on devising a safe subset by adding compile and/or run time checks that the untrusted code is safe for some measure of safe.
Consider other Sandboxing Approaches
There is an interesting discussion for the case of python here:
https://stackoverflow.com/questions/3688708/python-safe-sandbox
Maybe eval is too general?
Eval is often much more general that you require.
For example in the case of attacks like SQL injection maybe you don't need to be able to execute an arbitrary query maybe its enough to specify a table and key.
An example of similar kind of injection attack can occur if you delegate to something via text like
 doSomething --parseString $SomeStringInFormatX

In this case you could possibly attack via something like:
 "parseThis --acommand line option ;a new command altogether"

Using -- to start another command line option or ; to start a new command if doSomething is evaluated directly.
Whereas if the code to be parsed is in a file the attack surface is limited to the capabilities allowed when parsing a file of type X.
So you could instead say:
 doSomething --parseFile $SomeFileInFormatX

Or better skip the text altogether and have a function:
 doSomething(SomeFileNameInFormatX: path)


I should add that many of these approaches have risks. In TCL, for example, you can add commands to the inner interpreter and make it unsafe.
Also I don't know know if there is any proof that the "safe" subset cannot be circumvented.
The only surefire way to secure untrusted code would be running proofs on untrusted code and that is a hard problem.
Look for references like for example - https://www.cylab.cmu.edu/news/2022/10/11-provably-safe-sandboxing.html

Also you mention making eval safe by design and specifically not considering OS-level mitigations but you simply cannot ignore those.
For example, if you allow memory allocation than you will have to provide a way limit it as a function of your runtime or you allow a attack that will exhaust your memory. Sometimes the OS can help you there. For example, with posix and linux you can set resource limits. If the OS doesn't go far enough you will have to add similar things to your runtime. The more you do that the more your runtime will begin to ressemble an OS in some aspects.
It is a perfectly valid approach to say I don't want to have to worry too much about that and instead use external sandboxing solutions be they OS sandboxes, containers (docker etc), unikernals or virtualisation. As an added bonus you can potentially 'trust' systems that aren't part of your language at all. Using docker to implement 'eval' might be a bit of a sledgehammer but that sledgehamemr is a useful tool in its own right.
> **Comments:**
> **username_10** (2023-09-01): I would be interested to hear about examples (assuming they exist) where safeTCL has been defeated other than by a careless choice of commands being added to the inner interpreter and also about similar approaches in other languages.  
---
