https://en.wikipedia.org/wiki/Lisp_reader
"Unlike most programming languages, Lisp supports parse-time execution of programs, called "read macros" or "reader macros". These are used to extend the syntax either in universal or program-specific ways."
read-string is a convenience over calling read itself as it will take a string rather than needing you to create a java.io.PushbackReader yourself.
As such read and read-string were implemented as core to Clojure's self interpretation and implementation, not as part of a general safe serialization API.
Unfortunately the temptation was to reach for read-string for de-serialization in general as it was so convenient and in the core. In a dev setting where you control and trust all input that is fine. In other contexts it definitely is not!
(let [a #d (+ b c)] ...)
So the #d reader macro has access to the following form, but gets ignored at a higher level (i.e. when the "let" form is processed)
(def #=(symbol "foo") :bar)
Gets read as (def foo :bar) (read-string "#=(launch-the-missiles)") ;; don't let randos launch missiles
(binding [*read-eval* false]
(read-eval "#=(launch-missiles!)"))