>From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Pavel Sanda <sanda () lyx org>
Date: Thu, 16 Jul 2026 19:06:25 +0200
Subject: [PATCH] Hardening case 00d - arbitrary command execution via bibtex_command

A document-set \bibtex_command reaches two sinks:
- the preview pipeline, where --bibtex= feeds lyxpreview_tools.py,
- the export bibtex call, where parsecmd extracts <> redirection (file overwrite)
  (and/or injects code via metachars - win only).

Fires on export and on instant preview of a citation (possibly just load).

Tier 00 hotfix: drop --bibtex= from the preview; reject the redirection/metas.
Tier 01 DiD will land in master (canonical split).
Tier 02 strings will land in later 2.5.x (prefs hint).

Assisted-by: Claude Opus 4.8
---
 src/BufferParams.cpp           | 22 ++++++++++++++++++++--
 src/graphics/PreviewLoader.cpp |  7 ++++++-
 2 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp
index 6e8abdf2ac..f98b9cdbf7 100644
--- a/src/BufferParams.cpp
+++ b/src/BufferParams.cpp
@@ -4498,8 +4498,26 @@ string const BufferParams::getBibtexCommand(string const & cmd, bool const warn)
 string const BufferParams::bibtexCommand(bool const warn) const
 {
 	// Return document-specific setting if available
-	if (bibtex_command != "default")
-		return getBibtexCommand(bibtex_command, warn);
+	if (bibtex_command != "default") {
+
+		// Block redirection on the export bibtex call.
+		// Temporary hotfix, longterm solution needs structural
+		// split between program and options.
+		//
+		// Windows need wider set as it sinks to shell (unlike linux/mac).
+#if defined(_WIN32)
+		static char const * const SUSPECT_CHARS = "<>\"\\\t\n" "&|()^%;";
+#else
+		static char const * const SUSPECT_CHARS = "<>\"\\\t\n";
+#endif
+		if (bibtex_command.find_first_of(SUSPECT_CHARS) == string::npos)
+			return getBibtexCommand(bibtex_command, warn);
+		if (warn)
+			frontend::Alert::warning(
+				_("Requested bibliography command rejected"),
+				_("The bibliography processor command contains prohibited characters."));
+		// fall through to the lyxrc-driven selection below
+	}
 
 	// If we have "default" in document settings, consult the prefs
 	// 1. Japanese (uses a specific processor)
diff --git a/src/graphics/PreviewLoader.cpp b/src/graphics/PreviewLoader.cpp
index 0d185b4350..3c52bcbf79 100644
--- a/src/graphics/PreviewLoader.cpp
+++ b/src/graphics/PreviewLoader.cpp
@@ -685,7 +685,12 @@ void PreviewLoader::Impl::startLoading(bool wait)
 	}
 
 	cs << latexparam;
-	cs << " --bibtex=" << quoteName(buffer_.params().bibtexCommand());
+
+	// --bibtex= allows document-controlled arbitrary code
+	// execution in lyxpreview_tools.py. Tradeoff when disabling
+	// it is unresolved citations inside math/ERT preview.
+	//cs << " --bibtex=" << quoteName(buffer_.params().bibtexCommand());
+
 	if (buffer_.params().bufferFormat() == "lilypond-book")
 		cs << " --lilypond";
 
