From ac57e22b87dff954d668929e4f24972afdeb2dab Mon Sep 17 00:00:00 2001
From: ews-pgasser
Date: Thu, 6 Aug 2026 15:13:27 +0200
Subject: [PATCH] fix: allow docker compose command chaining
---
packages/server/src/utils/builders/compose.ts | 21 +++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/packages/server/src/utils/builders/compose.ts b/packages/server/src/utils/builders/compose.ts
index 1694a48ed..89851d84c 100644
--- a/packages/server/src/utils/builders/compose.ts
+++ b/packages/server/src/utils/builders/compose.ts
@@ -70,7 +70,8 @@ Compose Type: ${composeType} ✅`;
// Shell control characters that must never appear in a user-provided compose
// command: they would let it break out of the `docker ${command}` invocation
// into arbitrary host commands. A normal docker compose CLI line never needs them.
-const UNSAFE_COMPOSE_COMMAND = /[;&|`$(){}<>\n\\]/;
+// Removed '&' from the blocklist to allow '&&' chaining
+const UNSAFE_COMPOSE_COMMAND = /[;|`$(){}<>\n\\]/;
const sanitizeCommand = (command: string) => {
const sanitizedCommand = command.trim();
@@ -81,8 +82,24 @@ const sanitizeCommand = (command: string) => {
);
}
- const parts = sanitizedCommand.split(/\s+/);
+ if (sanitizedCommand.includes("&")) {
+ // Block single '&' (e.g., backgrounding tasks) or malformed chains like '&&&'
+ if (/(? cmd.trim());
+ const isSafeChain = chains.slice(1).every((cmd) =>
+ cmd.startsWith("docker compose ") || cmd.startsWith("docker-compose ")
+ );
+
+ if (!isSafeChain) {
+ throw new Error("Chained commands must strictly start with 'docker compose '");
+ }
+ }
+
+ const parts = sanitizedCommand.split(/\s+/);
const restCommand = parts.map((arg) => arg.replace(/^"(.*)"$/, "$1"));
return restCommand.join(" ");