diff --git a/esp/services/ws_workunits/ws_workunitsHelpers.cpp b/esp/services/ws_workunits/ws_workunitsHelpers.cpp index 6532f42acdc..5446e062a8d 100644 --- a/esp/services/ws_workunits/ws_workunitsHelpers.cpp +++ b/esp/services/ws_workunits/ws_workunitsHelpers.cpp @@ -4496,7 +4496,11 @@ void CWsWuFileHelper::zipZAPFiles(const char* parentFolder, const char* zapFiles else zipCommand.setf("cd %s\nzip -r", parentFolder); if (!isEmptyString(passwordReq)) - zipCommand.append(" --password ").append(passwordReq); + { + StringBuffer sanitizedPassword; + sanitizeCommandArg(passwordReq, sanitizedPassword); + zipCommand.append(" --password ").append(sanitizedPassword); + } zipCommand.append(" ").append(zipFileNameWithFullPath).append(" ").append(zapFiles); int zipRet = system(zipCommand); if (zipRet != 0) diff --git a/system/jlib/jstring.cpp b/system/jlib/jstring.cpp index 7e581f2503a..1f6492b4bef 100644 --- a/system/jlib/jstring.cpp +++ b/system/jlib/jstring.cpp @@ -2983,3 +2983,32 @@ const void * jmemmem(size_t lenHaystack, const void * haystack, size_t lenNeedle return nullptr; } + +/** + * For preventing command injection, sanitize the argument to be passed to the system command. + * - Quote the entire argument with single quotes to prevent interpretation of shell metacharacters. + * - Since a single-quoted string can't contain single quotes, even escaped, replace each single + * quote in the argument with the sequence '"'"' . That closes the single quoted string, appends + * a literal single quote, and reopens the single quoted string + */ +StringBuffer& sanitizeCommandArg(const char* arg, StringBuffer& sanitized) +{ +#if defined(__linux__) || defined(__APPLE__) + if (!isEmptyString(arg)) + { + size_t len = strlen(arg); + sanitized.append('\''); + for (size_t i = 0; i < len; i++) + { + if (arg[i] == '\'') + sanitized.append(R"('"'"')"); + else + sanitized.append(arg[i]); + } + sanitized.append('\''); + } +#else + sanitized.append(arg); +#endif + return sanitized; +} diff --git a/system/jlib/jstring.hpp b/system/jlib/jstring.hpp index d61b7fb7a1f..f1ece8d0caa 100644 --- a/system/jlib/jstring.hpp +++ b/system/jlib/jstring.hpp @@ -659,4 +659,7 @@ extern jlib_decl void ensureSeparator(StringBuffer & out, char separator); //Search for one block of bytes within another block of bytes - memmem is not standard, so we provide our own extern jlib_decl const void * jmemmem(size_t lenHaystack, const void * haystack, size_t lenNeedle, const void *needle); +// For preventing command injection, sanitize the argument to be passed to the system command +extern jlib_decl StringBuffer& sanitizeCommandArg(const char* arg, StringBuffer& sanitized); + #endif