diff --git a/config.py b/config.py index abadd7c..afaadf7 100644 --- a/config.py +++ b/config.py @@ -1,6 +1,6 @@ # Configuration and constants for MacroPad Server -VERSION = "1.1.0" +VERSION = "1.1.1" DEFAULT_PORT = 40000 SETTINGS_FILE = "settings.json" diff --git a/macro_manager.py b/macro_manager.py index 4c94b19..6c9e2c4 100644 --- a/macro_manager.py +++ b/macro_manager.py @@ -416,15 +416,23 @@ class MacroManager: elif cmd_type == "app": # Launch application. - # SECURITY: shell=True was removed to kill shell-metacharacter - # injection (no ; && | $() chaining). We tokenize the command - # and exec the program directly without a shell. + # SECURITY: never use shell=True — that would allow shell-metacharacter + # injection (; && | $() chaining, redirection). Both branches below run + # without a shell, so the command can only launch a program with args. command = cmd.get("command", "") if command: try: - args = shlex.split(command, posix=(os.name != "nt")) - if args: - subprocess.Popen(args) + if os.name == "nt": + # Windows: pass the string so CreateProcess parses it + # (correctly handling quoted paths like "C:\Program + # Files\app.exe"). shell=False means no cmd.exe, so no + # metacharacter chaining. + subprocess.Popen(command) + else: + # POSIX: split into an argv list; no shell involved. + args = shlex.split(command) + if args: + subprocess.Popen(args) except Exception as e: print(f"Error launching app command: {e}") diff --git a/version.txt b/version.txt index 1cc5f65..8cfbc90 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.1.0 \ No newline at end of file +1.1.1 \ No newline at end of file