Describe the bug
As input parameters are passed to the action as environment variables, and exec() reuses the action's environment by default, this means the input parameters will probably be visible to the subprocess. If any secrets are being passed via parameters, they will be visible too.
To Reproduce
Steps to reproduce the behavior:
fooawait exec.exec('sh', ['-c', 'echo foo==$INPUT_FOO'])Expected behavior
I would expect exec.exec() to strip input parameters from the environment used to run the subprocess by default. If there are cases where it is desirable to pass input parameters to the subprocess, this feels like it should be opt-in.
Add any other context about the problem here.
Additional context
While writing an action that took a login token for an online service as an input parameter, I was trying to be careful not to leak the secret: some commands I need to run have the secret passed via command line, and others don't need it. In retrospect it seems obvious that the secrets would be visible to all subprocesses through the environment variables, but it wasn't obvious from the toolkit documentation.
Toolkit exec for subprocesses has an optional arg to specify what the env dictionary looks like.
https://github.com/actions/toolkit/blob/master/packages/exec/src/interfaces.ts#L10
However, it is an interesting question whether we should strip INPUT_ vars. Right now, it would have to be a blanket INPUT_ strip unless we loaded up the action yml
I've used the env option when I wanted to pass additional environment variables to the subprocess. This was more about whether the API should be safe by default.
Stripping all INPUT_* environment variables seems like it should be fine. If there are actions that spawn subprocessed that care about an INPUT_* environment variable, chances are that it is a real input parameter.
An alternative would be for @actions/core to remove the variables from process.env. That is the approach taken by various systemd libraries that deal with configuration information passed through environment variables that should not be passed on to subprocesses. This seems more likely to cause compatibility problems though, if an action mixes calls to core.getInput with direct access to the environment.
I think INPUT_* environment variables should be filtered out. Various famous GitHub Actions receive GitHub API token as input:
it is a common case to use input for passing sensitive values like GitHub token. When using actions/exec for those actions, the sensitive values will be leaked to subprocesses.
If subprocess really requires some INPUT_* environment variables, it would be a good design to add INPUT_* values by env option. A user can explicitly set the necessary INPUT_* variables instead of passing all of them implicitly
``javascript
// Assume some_command requires INPUT_FOO. Even in the case, theenvvalue can setINPUT_FOO` value.
await exec.exec('some_command', ['args'], {
env: {
INPUT_FOO: '...'
}
});
Closing since this issue is stale (limited initial activity, and none for a over a year). The current solution is to use ExecOptions.env
If we do this change, we need to major version the toolkit since this would be a breaking change. Some folks likely rely on this behavior today - i.e. their logic is written in a different scripting language or even compiled binary (have seen this in the past).
Note, inheriting the env dictionary is also the default of Node.js and common scripting languages (bash, sh, ps, cmd). OS default too
Might be good to consider for the next major version
Chatted w/ @luketomlinson and @thboop offline. Let's track for next major version. Reopening for now, feel free to close again after this is tracked for next version (or leave open depending on however you decide to track)
Most helpful comment
I think
INPUT_*environment variables should be filtered out. Various famous GitHub Actions receive GitHub API token as input:it is a common case to use input for passing sensitive values like GitHub token. When using actions/exec for those actions, the sensitive values will be leaked to subprocesses.
If subprocess really requires some
INPUT_*environment variables, it would be a good design to addINPUT_*values byenvoption. A user can explicitly set the necessaryINPUT_*variables instead of passing all of them implicitly``
javascript // Assume some_command requires INPUT_FOO. Even in the case, theenvvalue can setINPUT_FOO` value.await exec.exec('some_command', ['args'], {
env: {
INPUT_FOO: '...'
}
});