GitHub Actions workflows support special workflow commands that allow workflows to interact with the runner. These commands can be invoked by
printing specially crafted messages to the standard output. For example, ::set-mask can be used to mask sensitive values in the workflow
logs and ::error to terminate execution with a useful error message.
Two of such commands, ::set-env and ::add-path, allow setting arbitrary environment variables and modifying the system
PATH for the subsequent workflow steps. In 2020, these commands were deprecated and disabled by default due to security concerns. However,
ACTIONS_ALLOW_UNSECURE_COMMANDS environment variable can still be used to re-enable them.
If this environment variable is set, the runner will process ::set-env and ::add-path commands printed to the standard
output. If an adversary can influence the content printed to the standard output (e.g., by injecting something into the build logs), they could use
these commands to manipulate the runtime environment.
When user-supplied values are used to manipulate environment variables, an attacker can supply carefully chosen values that cause the system to behave unexpectedly. This can be used to execute arbitrary commands as well as affect the behavior of other tools and scripts executed after the injection point. In most cases, this leads to arbitrary code execution on the system.
It is important to note, that these commands are triggered by printing to standard output. Therefore, this issue can be exploited if an attacker can influence the output of any command executed during the workflow.
The consequences of a successful attack can be severe and far-reaching:
Attackers can extract sensitive information from the runner environment, including:
Successful command injection allows attackers to:
Compromised workflows can be used to:
Attackers may be able to:
The impact is particularly severe because GitHub Actions runners often have elevated privileges and access to sensitive resources, making them attractive targets for attackers.
To fix this issue, remove setting of the ACTIONS_ALLOW_UNSECURE_COMMANDS environment variable, and replace the use of
::set-env and ::add-path with their safe alternatives:
$GITHUB_ENV environment variable. For example, to make a an environment variable named
VARIABLE to value for the subsequent workflows steps, you can do the following:
# This is equivalent to `export VARIABLE=value` across stpes echo "VARIABLE=value" >> $GITHUB_ENV
$GITHUB_PATH environment variable. For example, to add
/new/path to the PATH for the subsequent workflow steps, you can do the following:
# This is equivalent to `export PATH=/new/path:$PATH` across steps echo "/new/path" >> $GITHUB_PATH
name: "Example"
jobs:
set_env:
runs-on: ubuntu-latest
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true # Noncompliant
steps:
- run: |
echo "::set-env name=MESSAGE::hello"
- run: |
echo "Message: $MESSAGE"
name: "Example"
jobs:
set_env:
runs-on: ubuntu-latest
steps:
- run: |
echo "MESSAGE::hello" >> $GITHUB_ENV
- run: |
echo "Message: $MESSAGE"
add-path and
set-env Runner commands are processed via stdout