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

Reply via email to