v0.3.1: eliminate RCE via *read-eval* nil (Parser RCE Elimination)
Some checks failed
Deploy (Gitea) / deploy (push) Failing after 3s

Wrap read-from-string/read with (let ((*read-eval* nil)) ...) at three
untrusted-input code paths:

1. think() in core-loop-reason — LLM output parsing. LLM output is
   untrusted by definition; #.(shell ...) in a response must not execute.

2. action-system-execute in core-loop-act — :system :eval path processes
   untrusted payload code from the signal pipeline.

3. load-memory-from-disk in core-memory — memory.snap file could be
   corrupted or planted in ~/, must not execute #. reader macros.

Adds test-read-eval-rce-blocked to pipeline-reason-suite: mocks a
backend returning malicious output containing #.(setf ...), verifies
no side effects occur and safe fallback is returned.

RED proof recorded: *read-eval* T + #.(setf ...) → :PWNED (RCE active)
GREEN proof:    *read-eval* NIL → reader-error caught (RCE blocked)

Test: reason 12/0, full suite 88/0
This commit is contained in:
2026-05-06 16:38:59 -04:00
parent d50d72656c
commit a31f19045a
6 changed files with 38 additions and 6 deletions

View File

@@ -349,7 +349,7 @@ Restores memory state from a previously saved snapshot file. Called during boot
(when (uiop:file-exists-p path)
(handler-case
(with-open-file (stream path :direction :input)
(let ((data (read stream nil)))
(let ((data (let ((*read-eval* nil)) (read stream nil))))
(when data
(let ((memory-alist (getf data :memory)) (history-alist (getf data :history-store)))
(setf *memory-store* (make-hash-table :test 'equal :size (length memory-alist)))