git clone ''

(ql:quickload :cl-secure-read)


Secure the lisp reader in spirit of Let Over Lambda. See section “Reader Security” on to get the initial idea.


CL-USER> (ql:quickload 'cl-secure-read)
CL-USER> (in-package cl-secure-read)
;; Define a function DEFAULT-RFS, which is a restricted version of READ-FROM-STRING
CL-SECURE-READ> (define-secure-read-from-string default-rfs :fail-value "caboom!")
CL-SECURE-READ> (default-rfs "123") ; this will read in number 123, as expected ...
;; ... and this will hopefully just return "caboom!",
;; not executing the removal shell-command.
CL-SECURE-READ> (default-rfs "#.(shell-eval \"rm -rf ./\"")

Now exports 4 macro:

Here are some notable parameters to macro, which control the behavior of resulting restricted reader:

Here is a full-fledged example, using most of the described features

;; use readtable :clesh, allow comments, special clesh bang-syntax, allow read-eval,
;; do not force standard-io-syntax, in case of failure return string "caboom!"
(let ((safe-read-from-string-whitelist '(#\; #\! (#\# #\.) :allow-read-eval :keep-io-syntax)))
  (define-secure-read-from-string not-so-strict-read-from-string :readtable :clesh :fail-value "caboom!"))

(not-so-strict-read-from-string "asdf") ; this will read-in symbol ASDF
(not-so-strict-read-from-string "#(1 2 3)") ; and this will return "caboom!"
;; since we've requested not to force io-syntax, we may control read-eval dynamically.
;; Here returns "caboom!", even though *READ-EVAL* was enabled in the definition
(let (*read-eval*)
  (not-so-strict-read-from-string "#.(1 2 3)"))

Syntax of black/white-lists

Black/white list may contain:

If BLACKLIST is NIL, all the macro-characters and dispatching macro-characters of the readtable are disabled, unless they are explicitly enabled in the WHITELIST. To actually enable all the macrocharacters in the readtable, use something like lisp :BLACKLIST (:t)