From 1e2376f71b8206c687df6654f36574e858b6730d Mon Sep 17 00:00:00 2001 From: Safal Piya Date: Sat, 11 Oct 2025 18:44:21 +0545 Subject: [PATCH 1/2] fix: Escape shell arguments for safety --- backend/dockerMailserver.js | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/backend/dockerMailserver.js b/backend/dockerMailserver.js index f0c4a9c..4df906e 100644 --- a/backend/dockerMailserver.js +++ b/backend/dockerMailserver.js @@ -22,6 +22,18 @@ function debugLog(message, data = null) { } } +/** + * Escapes a string for safe use in shell commands by wrapping it in single quotes + * and escaping any single quotes within the string + * @param {string} arg - Argument to escape + * @return {string} Escaped argument safe for shell execution + */ +function escapeShellArg(arg) { + // Replace single quotes with '\'' (end quote, escaped quote, start quote) + // Then wrap the entire string in single quotes + return "'" + arg.replace(/'/g, "'\\''") + "'"; +} + /** * Executes a command in the docker-mailserver container * @param {string} command Command to execute @@ -143,7 +155,9 @@ async function getAccounts() { async function addAccount(email, password) { try { debugLog(`Adding new email account: ${email}`); - await execSetup(`email add ${email} ${password}`); + await execSetup( + `email add ${escapeShellArg(email)} ${escapeShellArg(password)}` + ); debugLog(`Account created: ${email}`); return { success: true, email }; } catch (error) { @@ -157,7 +171,9 @@ async function addAccount(email, password) { async function updateAccountPassword(email, password) { try { debugLog(`Updating password for account: ${email}`); - await execSetup(`email update ${email} ${password}`); + await execSetup( + `email update ${escapeShellArg(email)} ${escapeShellArg(password)}` + ); debugLog(`Password updated for account: ${email}`); return { success: true, email }; } catch (error) { @@ -171,7 +187,7 @@ async function updateAccountPassword(email, password) { async function deleteAccount(email) { try { debugLog(`Deleting email account: ${email}`); - await execSetup(`email del ${email}`); + await execSetup(`email del ${escapeShellArg(email)}`); debugLog(`Account deleted: ${email}`); return { success: true, email }; } catch (error) { @@ -229,7 +245,9 @@ async function getAliases() { async function addAlias(source, destination) { try { debugLog(`Adding new alias: ${source} -> ${destination}`); - await execSetup(`alias add ${source} ${destination}`); + await execSetup( + `alias add ${escapeShellArg(source)} ${escapeShellArg(destination)}` + ); debugLog(`Alias created: ${source} -> ${destination}`); return { success: true, source, destination }; } catch (error) { @@ -243,7 +261,9 @@ async function addAlias(source, destination) { async function deleteAlias(source, destination) { try { debugLog(`Deleting alias: ${source} => ${destination}`); - await execSetup(`alias del ${source} ${destination}`); + await execSetup( + `alias del ${escapeShellArg(source)} ${escapeShellArg(destination)}` + ); debugLog(`Alias deleted: ${source} => ${destination}`); return { success: true, source, destination }; } catch (error) { From 12e12f5fc2ab40f4e301014cd1561549ab9dba2b Mon Sep 17 00:00:00 2001 From: Safal Piya Date: Mon, 13 Oct 2025 02:15:54 +0545 Subject: [PATCH 2/2] refactor: Template literal string concat in `escapeShellArg` function --- backend/dockerMailserver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/dockerMailserver.js b/backend/dockerMailserver.js index 4df906e..834bdfe 100644 --- a/backend/dockerMailserver.js +++ b/backend/dockerMailserver.js @@ -31,7 +31,7 @@ function debugLog(message, data = null) { function escapeShellArg(arg) { // Replace single quotes with '\'' (end quote, escaped quote, start quote) // Then wrap the entire string in single quotes - return "'" + arg.replace(/'/g, "'\\''") + "'"; + return `'${arg.replace(/'/g, "'\\''")}'`; } /**