Merge pull request #4997 from ews-pgasser/fix/chaining-canary

fix: allow docker compose command chaining
(cherry picked from commit 91258d00ad)

[skip ci]
This commit is contained in:
Narciso E. Núñez Arias
2026-08-07 14:34:29 +00:00
committed by Dokploy Bot
parent d3a873a6f5
commit 6293a39187
2 changed files with 94 additions and 3 deletions
+28 -2
View File
@@ -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,33 @@ const sanitizeCommand = (command: string) => {
);
}
const parts = sanitizedCommand.split(/\s+/);
if (sanitizedCommand.includes("&")) {
// Block single '&' (e.g., backgrounding tasks) or malformed chains like '&&&'
if (
/(?<!&)&(?!&)/.test(sanitizedCommand) ||
sanitizedCommand.includes("&&&")
) {
throw new Error("Single '&' is not allowed. Use '&&' for chaining.");
}
// Split by '&&' and check that every chained command (skipping the first one) is safe
const chains = sanitizedCommand.split("&&").map((cmd) => 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(" ");