[LyX/master] Hardening case 00g - arbitrary command execution via mangled filename extension

Pavel Sanda <[email protected]>
Newsgroups gmane.editors.lyx.cvs
Message-ID <[email protected]>
commit a3546130ab5732854f0abafac1ef42e16b365ab5
Author: Pavel Sanda <[email protected]>
Date:   Thu Jun 11 02:37:55 2026 +0200

    Hardening case 00g - arbitrary command execution via mangled filename extension
    
    mangledFileName() sanitized the base of a copied file's name but re-attached
    its extension unsanitized; the mangled name reaches shell command lines in
    shipped conversion helpers on export, so a hostile graphics extension injects
    arbitrary commands.
    
    Fires on export.
    
    Tier 00 fix: sanitize the extension too in mangledFileName(), drop ;=
    
    Assisted-by: Claude Opus 4.7
---
 src/support/FileName.cpp  | 12 +++++++-----
 src/support/filetools.cpp |  3 ++-
 2 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/src/support/FileName.cpp b/src/support/FileName.cpp
index e49f76e90c..2b8e0243f3 100644
--- a/src/support/FileName.cpp
+++ b/src/support/FileName.cpp
@@ -990,11 +990,11 @@ string DocFileName::mangledFileName(string const & dir, bool encrypt_path) const
 	// xHTML route
 	// we use hash instead of counter to get stable filenames in export directory
 	if (encrypt_path) {
-		// sanitization probably not neccessary for xhtml, but won't harm
 		string sanfn = support::changeExtension(onlyFileName(), string());
 		sanfn = sanitizeFileName(sanfn);
-		// Add the extension back on
-		sanfn = support::changeExtension(sanfn, getExtension(onlyFileName()));
+		// extension is user-controlled string, suppress metacharacters
+		sanfn = support::changeExtension(sanfn,
+				sanitizeFileName(getExtension(onlyFileName())));
 
 		//various filesystems have filename limit around 2^8
 		if (sanfn.length() > 230)
@@ -1014,8 +1014,10 @@ string DocFileName::mangledFileName(string const & dir, bool encrypt_path) const
 		mname = support::changeExtension(name, string());
 		// The mangled name must be a valid LaTeX name.
 		mname = sanitizeFileName(mname);
-		// Add the extension back on
-		mname = support::changeExtension(mname, getExtension(name));
+		// Add the extension back on, but sanitize from metachars,
+		// it's user-controlled string
+		mname = support::changeExtension(mname,
+				sanitizeFileName(getExtension(name)));
 
 		// Prepend a counter to the filename. This is necessary to make
 		// the mangled name unique, see truncation below.
diff --git a/src/support/filetools.cpp b/src/support/filetools.cpp
index 705ec8d365..a4986f1ba2 100644
--- a/src/support/filetools.cpp
+++ b/src/support/filetools.cpp
@@ -1401,9 +1401,10 @@ std::string sanitizeFileName(const std::string & str)
 	// are forbidden: '/', '.', ' ', and ':'.
 	// On windows it is not possible to create files with '<', '>' or '?'
 	// in the name.
+	// We forbid ';', '=' as they could become active in shell.
 	static std::string const keep = "abcdefghijklmnopqrstuvwxyz"
 	                           "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-	                           "+-0123456789;=";
+	                           "+-0123456789";
 
 	std::string name = str;
 	string::size_type pos = 0;
-- 
lyx-cvs mailing list
[email protected]
https://lists.lyx.org/mailman/listinfo/lyx-cvs
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.