Secure coding practices for tasks
Use secure coding practices when you write tasks and help protect your system.
One of the methods attackers use to gain access to your systems is remote code execution, where by running an allowed script they gain access to other parts of the system and can make arbitrary changes. Because Bolt executes scripts across your infrastructure, it is important to be aware of certain vulnerabilities, and to code tasks in a way that guards against remote code execution.
Adding task metadata that validates input is one way to reduce
vulnerability. When you require an enumerated (enum
) or other non-string types, you prevent improper data
from being entered. An arbitrary string parameter does not have this assurance.
For example, if your task has a parameter that selects from several operational modes that are passed to a shell command, instead of
String $mode = 'file'
use
Enum[file,directory,link,socket] $mode = file
If your task has a parameter that identifies a file on disk, ensure that a user can't specify a relative path that takes them into areas where they shouldn't be. Reject file names that have slashes.
Instead of
String $path
use
Pattern[/\A[^\/\\]*\z/] $path
In addition to these task restrictions, different scripting languages each have their own ways to validate user input.
PowerShell
In PowerShell, code injection exploits calls that
specifically evaluate code. Do not call Invoke-Expression
or Add-Type
with
user input. These commands evaluate strings as C# code.
Reading sensitive files or overwriting critical files can be less obvious. If you
plan to allow users to specify a file name or path, use Resolve-Path
to verify that the path doesn't go outside the locations
you expect the task to access. Use Split-Path -Parent
$path
to check that the resolved path has the desired path as a
parent.
For more information, see PowerShell Scripting and Powershell's Security Guiding Principles.
Bash
In Bash and other command shells, shell command injection takes advantage of poor shell implementations. Put quotations marks around arguments to prevent the vulnerable shells from evaluating them.
Because the eval
command evaluates all arguments with
string substitution, avoid using it with user input; however you can use eval
with sufficient quoting to prevent substituted
variables from being executed.
Instead of
eval "echo $input"
use
eval "echo '$input'"
These are operating system-specific tools to validate file paths: realpath
or readlink -f
.
Python
In Python malicious code can be introduced through commands like eval
, exec
, os.system
, os.popen
, and
subprocess.call
with shell=True
. Use subprocess.call
with
shell=False
when you include user input in a
command or escape variables.
Instead of
os.system('echo '+input)
use
subprocess.check_output(['echo', input])
Resolve file paths with os.realpath
and confirm them
to be within another path by looping over os.path.dirname
and comparing to the desired path.
For more information on the vulnerabilities of Python or how to escape variables, see Kevin London's blog post on Dangerous Python Functions.
Ruby
In Ruby, command injection is introduced through
commands like eval
, exec
, system
, backtick (``) or %x()
execution, or the Open3 module. You can safely call
these functions with user input by passing the input as additional arguments instead
of a single string.
Instead of
system("echo #{flag1} #{flag2}")
use
system('echo', flag1, flag2)
Resolve file paths with Pathname#realpath
, and
confirm them to be within another path by looping over Pathname#parent
and comparing to the desired path.
For more information on securely passing user input, see the blog post Stop using backtick to run shell command in Ruby.