Welcome! Please see the About page for a little more info on how this works.

+1 vote
in Syntax and reader by

I'm new to clojure and trying to understand some security aspects of the language.

In the documentation I understand that binding a read-eval to unkown should deny execution of code.

But playing with the code under clojure.core/read-string it works properly by using clojure.tools.reader/read-string it does invoke.

I also saw that reader.edn does not invoke code but wanted to make sure no code will be executed even if one of our developers did a mistake and used clojure.tools.reader

Thanks in advance, Rotem


(binding [*read-eval* :unknown]
(clojure.tools.reader/read-string "#=(* 2 21)"))
=> 42

1 Answer

+1 vote

If they can "by mistake" include an additional library and invoke arbitrary code, then they can mistakenly do anything.

clojure.tools.reader has a similar dynamic var, clojure.tools.reader/*read-eval* that is used in the same way, so you'd need to bind both.

Understood, I would want to set one *read-eval* to unkown for testing to verify that no code is running just like clojure.core doesn't need a clojure.core/*read-eval* binding

And yes, in security I want to make sure developers are aware they want eval capabilities. I would recommend to put it by default to false, but this is a more core request

I would recommend to  add the proper documentation as this is not clear and can create code executions in places that we haven't thought possible
Does the text here on clojure.core/read and clojure.core/read-string clarify anything?  It was written several years ago when the clojure.edn namespace was added to Clojure with the doesn't-read-code-only-data variants of read functions, and still appears to me to be accurate: http://clojuredocs.org/clojure.core/read
Is the confusion here stemming from this doc not being explicit about which *read-eval* it is talking about?


I can see how someone who has read the core read/read-string docs might then read tools.reader's docs for its own read/read-string and not make the connection that it is talking about a separate clojure.tools.reader/*read-eval* rather than the core variable.

And I can see how folks binding the core variable might want it to apply "universally" (i.e., might also control a Contrib library's behavior -- on the assumption that Contrib libs fall under the Clojure org and therefore might be somewhat interdependent).
Sean, I think this is exactly what was my thoughts and confusion.

I see lots of clojure developers use the read-string without really understanding its impact on security and even when trying to disable it with the *read-eval* symbol it gets confusing, which I learned in this discussion I need to put the two bindings of different namespaces

I would want to have a binding I can put which I can be sure there will be no eval in those common read-string functions
A good approach would be educating developers about the insecurities of clojure.core/read and clojure.core/read-string, e.g. pointing them at the examples at the link I gave above.

Another would be to provide them with a couple of functions that you trust are safe, and recommend that they use those.  Comment them or write big long doc strings to your heart's content about why they are safer, and what is unsafe about the alternatives.

The ready-made replacements to use are for convenience of those making their code more safe.  Education is still required so they are aware the functions exist.
...and discouraging them from using the tools.reader functions -- it's a common transitive dependency so I can see how they'd discover it in a code base and think that using a "reader" namespace to read strings would be the obvious, right way to do things.