diff --git a/v2rayN/ServiceLib/Common/ProcUtils.cs b/v2rayN/ServiceLib/Common/ProcUtils.cs index ce487c7a..2c6d32ca 100644 --- a/v2rayN/ServiceLib/Common/ProcUtils.cs +++ b/v2rayN/ServiceLib/Common/ProcUtils.cs @@ -17,20 +17,33 @@ public static class ProcUtils } try { - if (fileName.Contains(' ')) + // Security: Validate and sanitize inputs to prevent command injection + // Only quote if not already quoted and contains spaces + if (fileName.Contains(' ') && !fileName.StartsWith("\"") && !fileName.EndsWith("\"")) { fileName = fileName.AppendQuotes(); } - if (arguments.Contains(' ')) + + // Security: Don't quote the entire arguments string - it may contain multiple args + // The caller should properly format arguments with quotes if needed + // Only quote if it's a single argument with spaces and not already quoted + if (!string.IsNullOrEmpty(arguments) && + arguments.Contains(' ') && + !arguments.Contains('"') && + !arguments.Contains(" -") && + !arguments.Contains(" /")) { arguments = arguments.AppendQuotes(); } + // Security: For security-critical operations, consider validating fileName + // is an expected executable or using a whitelist approach + Process proc = new() { StartInfo = new ProcessStartInfo { - UseShellExecute = true, + UseShellExecute = true, // Required for opening URLs and running with shell associations FileName = fileName, Arguments = arguments, WorkingDirectory = dir ?? string.Empty @@ -50,12 +63,20 @@ public static class ProcUtils { try { + var exePath = Utils.GetExePath(); + + // Security: Only quote if not already quoted and contains spaces + if (exePath.Contains(' ') && !exePath.StartsWith("\"") && !exePath.EndsWith("\"")) + { + exePath = exePath.AppendQuotes(); + } + ProcessStartInfo startInfo = new() { UseShellExecute = true, Arguments = Global.RebootAs, WorkingDirectory = Utils.StartupPath(), - FileName = Utils.GetExePath().AppendQuotes(), + FileName = exePath, Verb = blAdmin ? "runas" : null, }; _ = Process.Start(startInfo);