Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(core): properly escape shell commands (#5811)
* fix(core): properly escape shell commands Shell commands need to be carefully constructed to avoid command injection issues, and also to avoid issues with the shell interpreting input strings, e.g. parenthesis or glob characters. If possible, we should pass a command list for executing commands. For untrusted input values, one should use environment variables and access them from the shell script. Make sure to access them wrapped around double quotes, otherwise the script is prone to command injection attacks. Sometimes it is needed to construct a shell script to chain multuiple commands together. In this case, this commit introduces a utility function `commandListToShellScript`. It wraps every parameter in single quotes, escaping contained single quotes (for use in bash scripts). Joins the elements with a space character. Examples: ``` // returns `echo 'hello world'` commandListToShellScript(["echo", "hello world"]) // returns `echo 'hello'"'"'world'` commandListToShellScript(["echo", "hello'world"]) // returns `echo ''"'"'; exec ls /'` commandListToShellScript(["echo", "'; exec ls /"]) ``` Caveat: This is only safe if the command is directly executed. It is not safe, if you wrap the output of this in double quotes, for instance. ``` // SAFE exec(["sh", "-c", ${commandListToShellScript(["some", "command", "--with" untrustedInput])}]) exec(["sh", "-c", dedent` set -e echo "running command..." ${commandListToShellScript(["some", "command", "--with" untrustedInput])} echo "done" `]) // UNSAFE! don't do this const commandWithUntrustedInput = commandListToShellScript(["some", "command", "--with" untrustedInput]) exec(["sh", "-c", `some_var="${commandWithUntrustedInput}"; echo "$some_var"`]) ``` The second is UNSAFE, because we can't know that the /double quotes/ need to be escaped here. If you can, use environment variables instead of this, to pass untrusted values to shell scripts, e.g. if you do not need to construct a command with untrusted input. ``` // SAFE exec(["sh", "-c", `some_var="$UNTRUSTED_INPUT"; echo "$some_var"`], { env: { UNTRUSTED_INPUT: untrustedInput } }) ``` * fix: tests * revert: undo the escape of double quotes introduced in #5712 Double quotes in buildkit commands don't need to be escaped as they are not interpreted by the shell anymore now. * fix: tests * fix: allow empty values for build args #4081 * test: attempt fixing tests * fix: remove unnecessary JSON escape to fix artifacts * fix: allow globs in artifact source paths * revert: undo unnecessary changes * test: fix remaining tests
- Loading branch information
Showing
12 changed files
with
194 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* | ||
* Copyright (C) 2018-2024 Garden Technologies, Inc. <info@garden.io> | ||
* | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
*/ | ||
|
||
/** | ||
* Wraps every parameter in single quotes, escaping contained single quotes (for use in bash scripts). Joins the elements with a space character. | ||
* | ||
* Examples: | ||
* | ||
* // returns `echo 'hello world'` | ||
* commandListToShellScript(["echo", "hello world"]) | ||
* | ||
* // returns `echo 'hello'"'"'world'` | ||
* commandListToShellScript(["echo", "hello'world"]) | ||
* | ||
* // returns `echo ''"'"'; exec ls /'` | ||
* commandListToShellScript(["echo", "'; exec ls /"]) | ||
* | ||
* Caveat: This is only safe if the command is directly executed. It is not safe, if you wrap the output of this in double quotes, for instance. | ||
* | ||
* // SAFE | ||
* exec(["sh", "-c", ${commandListToShellScript(["some", "command", "--with" untrustedInput])}]) | ||
* exec(["sh", "-c", dedent` | ||
* set -e | ||
* echo "running command..." | ||
* ${commandListToShellScript(["some", "command", "--with" untrustedInput])} | ||
* echo "done" | ||
* `]) | ||
* | ||
* // UNSAFE! don't do this | ||
* | ||
* const commandWithUntrustedInput = commandListToShellScript(["some", "command", "--with" untrustedInput]) | ||
* exec(["sh", "-c", `some_var="${commandWithUntrustedInput}"; echo "$some_var"`]) | ||
* | ||
* The second is UNSAFE, because we can't know that the /double quotes/ need to be escaped here. | ||
* | ||
* If you can, use environment variables instead of this, to pass untrusted values to shell scripts, e.g. if you do not need to construct a command with untrusted input. | ||
* | ||
* // SAFE | ||
* | ||
* exec(["sh", "-c", `some_var="$UNTRUSTED_INPUT"; echo "$some_var"`], { env: { UNTRUSTED_INPUT: untrustedInput } }) | ||
* | ||
* @param command array of command line arguments | ||
* @returns string to be used as shell script statement to execute the given command. | ||
*/ | ||
export function commandListToShellScript(command: string[]) { | ||
return command.map((c) => `'${c.replaceAll("'", `'"'"'`)}'`).join(" ") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.