>From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Pavel Sanda Date: Thu, 16 Jul 2026 19:06:25 +0200 Subject: [PATCH] Hardening case 00e - arbitrary command execution via index_command A document-set \index_command was copied verbatim into the index-processor call on export, giving program substitution and <> redirection (file overwrite, same primitive as 00k), and/or code injection via metachars on windows. Fires on export. Tier 00 hotfix: accept only known index cmd, reject <> (+metas on win) Tier 01 DiD will land in master (canonical split, shared with 00d). Assisted-by: Claude Opus 4.8 --- src/Converter.cpp | 35 +++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/Converter.cpp b/src/Converter.cpp index 03172ac2ae..98f029376b 100644 --- a/src/Converter.cpp +++ b/src/Converter.cpp @@ -498,8 +498,39 @@ Converters::RetVal Converters::convert(Buffer const * buffer, && bp.encoding().package() == Encoding::japanese; runparams.use_indices = bp.use_indices; runparams.bibtex_command = bp.bibtexCommand(true); - runparams.index_command = (bp.index_command == "default") ? - string() : bp.index_command; + + // Accept only programs from fixed known list + string accepted_index_cmd; + if (bp.index_command != "default" && !bp.index_command.empty()) { + + // Block redirection (+ metas on Windows where it sinks to shell) +#if defined(_WIN32) + static char const * const SUSPECT_CHARS = "<>" "&|()^%;"; +#else + static char const * const SUSPECT_CHARS = "<>"; +#endif + bool const has_suspect = + bp.index_command.find_first_of(SUSPECT_CHARS) != string::npos; + if (!has_suspect) { + string supplied_prog; + split(bp.index_command, supplied_prog, ' '); + for (auto const & alt : lyxrc.index_alternatives) { + string alt_prog; + split(alt, alt_prog, ' '); + if (!supplied_prog.empty() + && supplied_prog == alt_prog) { + accepted_index_cmd = bp.index_command; + break; + } + } + } + if (accepted_index_cmd.empty()) + LYXERR0("Document-supplied index command '" + << bp.index_command << "' is not a recognised " + "index processor; falling back to default."); + } + + runparams.index_command = accepted_index_cmd; runparams.document_language = bp.language->lang(); // Some macros rely on font encoding runparams.main_fontenc = bp.main_font_encoding();