branch: elpa/flycheck
commit 79a599302a965d8cff554945db4fb470084a788d
Author: Bozhidar Batsov <[email protected]>
Commit: Bozhidar Batsov <[email protected]>

    [Fix #2159] Properly mitigate CVE-2024-53920 on Emacs 30+
    
    On Emacs 30+, disable the emacs-lisp checker for files not marked
    as trusted via `trusted-content`.  Byte-compilation triggers macro
    expansion which can execute arbitrary code, so the previous
    mitigation (disabling `enable-local-eval`) was insufficient.
---
 CHANGES.rst                             |  6 ++++++
 doc/languages.rst                       |  9 +++++++++
 flycheck-buttercup.el                   | 15 +++++++++++----
 flycheck.el                             | 21 ++++++++++++++++++++-
 test/specs/languages/test-emacs-lisp.el | 19 +++++++++++++++++++
 5 files changed, 65 insertions(+), 5 deletions(-)

diff --git a/CHANGES.rst b/CHANGES.rst
index 518729b994..a5a3d50744 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -28,6 +28,12 @@
   ``LC_ALL=C``, so the character encoding is left untouched.  ``LC_ALL=C``
   broke checkers reading UTF-8 input, such as ``hledger``.
 
+- [#2159]: Properly mitigate CVE-2024-53920 in the ``emacs-lisp`` checker
+  by requiring files to be marked as trusted (via ``trusted-content``) on
+  Emacs 30+.  Byte-compilation triggers macro expansion which can execute
+  arbitrary code, so the checker is now disabled for untrusted files.
+  ``emacs-lisp-checkdoc`` doesn't expand macros and stays enabled.
+
 36.0 (2026-02-19)
 ======================
 
diff --git a/doc/languages.rst b/doc/languages.rst
index 58f3de6be2..b9eace5325 100644
--- a/doc/languages.rst
+++ b/doc/languages.rst
@@ -350,6 +350,15 @@ to view the docstring of the syntax checker.  Likewise, 
you may use
 
       Check syntax with the built-in byte compiler.
 
+      On Emacs 30+, this checker is only enabled for files marked as
+      trusted via ``trusted-content`` (see :infonode:`(emacs)Safe File
+      Variables`), to mitigate CVE-2024-53920.  Byte-compilation involves
+      macro expansion which can execute arbitrary code, so untrusted files
+      must not be byte-compiled.  To use this checker, add your project
+      directories to ``trusted-content``.  The ``emacs-lisp-checkdoc``
+      checker doesn't expand macros and remains enabled for untrusted
+      files.
+
       .. defcustom:: flycheck-emacs-lisp-load-path
 
          The load path as list of strings.  Relative directories are expanded
diff --git a/flycheck-buttercup.el b/flycheck-buttercup.el
index 48ced63b37..01f5710bdf 100644
--- a/flycheck-buttercup.el
+++ b/flycheck-buttercup.el
@@ -253,15 +253,22 @@ with VALUE."
        (setenv var value))
      ,@body))
 
+;; `trusted-content' only exists on Emacs 30+; declare it so that the
+;; let-binding below is dynamic instead of lexical on older versions.
+(defvar trusted-content)
+
 (defmacro flycheck-buttercup-with-resource-buffer (resource-file &rest body)
   "Create a temp buffer from a RESOURCE-FILE and execute BODY.
 
 The absolute file name of RESOURCE-FILE is determined with
-`flycheck-buttercup-resource-filename'."
+`flycheck-buttercup-resource-filename'.  The resource file is
+marked as trusted via `trusted-content', so that checkers gated
+on `trusted-content-p' (e.g. `emacs-lisp') remain enabled."
   (declare (indent 1))
-  `(flycheck-buttercup-with-file-buffer
-       (flycheck-buttercup-resource-filename ,resource-file)
-     ,@body))
+  `(let ((trusted-content :all))
+     (flycheck-buttercup-with-file-buffer
+         (flycheck-buttercup-resource-filename ,resource-file)
+       ,@body)))
 
 
 ;;; Syntax checking in tests
diff --git a/flycheck.el b/flycheck.el
index e82aa09191..7b2c55f45e 100644
--- a/flycheck.el
+++ b/flycheck.el
@@ -8726,6 +8726,20 @@ This variable has no effect, if
          (member (file-name-nondirectory (buffer-file-name))
                  '("Cask" "Carton" ".dir-locals.el" ".dir-locals-2.el"))))))
 
+(defun flycheck--emacs-lisp-byte-compile-enabled-p ()
+  "Check whether to enable the Emacs Lisp byte compiler checker.
+
+On Emacs 30+, the checker is only enabled for trusted files, to
+mitigate CVE-2024-53920: byte-compilation involves macro expansion
+which can execute arbitrary code.  Customize `trusted-content' to
+mark files or directories as trusted.
+
+Checkdoc doesn't expand macros, so `emacs-lisp-checkdoc' stays
+enabled for untrusted files, like in Emacs core."
+  (and (flycheck--emacs-lisp-enabled-p)
+       (or (not (fboundp 'trusted-content-p))
+           (trusted-content-p))))
+
 (defun flycheck--emacs-lisp-checkdoc-enabled-p ()
   "Check whether to enable Emacs Lisp Checkdoc in the current buffer."
   (and (flycheck--emacs-lisp-enabled-p)
@@ -8735,6 +8749,11 @@ This variable has no effect, if
 (flycheck-define-checker emacs-lisp
   "An Emacs Lisp syntax checker using the Emacs Lisp Byte compiler.
 
+On Emacs 30+, this checker is only enabled for files the user has
+marked as trusted via the `trusted-content' variable, to mitigate
+CVE-2024-53920 (byte-compilation involves macro expansion which can
+execute arbitrary code).
+
 See Info Node `(elisp)Byte Compilation'."
   :command ("emacs" (eval flycheck-emacs-args)
             (eval
@@ -8784,7 +8803,7 @@ See Info Node `(elisp)Byte Compilation'."
      (flycheck-collapse-error-message-whitespace
       (flycheck-sanitize-errors errors))))
   :modes (emacs-lisp-mode lisp-interaction-mode)
-  :enabled flycheck--emacs-lisp-enabled-p
+  :enabled flycheck--emacs-lisp-byte-compile-enabled-p
   :predicate
   (lambda ()
     ;; Do not check buffers that should not be byte-compiled.  The checker
diff --git a/test/specs/languages/test-emacs-lisp.el 
b/test/specs/languages/test-emacs-lisp.el
index c850891f18..04be162af3 100644
--- a/test/specs/languages/test-emacs-lisp.el
+++ b/test/specs/languages/test-emacs-lisp.el
@@ -57,6 +57,25 @@
                 :to-equal
                 (seq-sort #'string-lessp checkdoc-relevant-vars)))))
 
+  (describe "Trusted content (CVE-2024-53920)"
+
+    (it "disables byte compilation for untrusted files"
+      (assume (fboundp 'trusted-content-p) "Requires Emacs 30+")
+      (flycheck-buttercup-with-resource-buffer 
"language/emacs-lisp/warnings.el"
+        (emacs-lisp-mode)
+        (let ((trusted-content nil))
+          (expect (flycheck-may-use-checker 'emacs-lisp)
+                  :not :to-be-truthy)
+          ;; Checkdoc doesn't expand macros, so it stays enabled
+          (expect (flycheck-may-use-checker 'emacs-lisp-checkdoc)
+                  :to-be-truthy))))
+
+    (it "enables byte compilation for trusted files"
+      (assume (fboundp 'trusted-content-p) "Requires Emacs 30+")
+      (flycheck-buttercup-with-resource-buffer 
"language/emacs-lisp/warnings.el"
+        (emacs-lisp-mode)
+        (expect (flycheck-may-use-checker 'emacs-lisp) :to-be-truthy))))
+
   (describe "Checker tests"
     (flycheck-buttercup-def-checker-test (emacs-lisp emacs-lisp-checkdoc) 
emacs-lisp nil
       (flycheck-buttercup-should-syntax-check

Reply via email to