-
Notifications
You must be signed in to change notification settings - Fork 12
Description
Summary
Vault secret values are resolved before CEL evaluation in model_resolver.ts:resolveVaultExpressions(). The current escaping chain prevents breaking out of a CEL string literal (backslash, double quote, single quote, backtick, whitespace), but does not escape shell metacharacters.
When a vault secret is injected via CEL into the run field of a command/shell model, characters such as $, &, |, ;, (, ) pass through unescaped into the shell command.
Attack Path
A user writes a model definition like:
run: "echo " + vault.get('my-vault', 'SECRET') + " done"If SECRET contains $(cat /etc/passwd), the vault resolution step produces the CEL expression:
"echo " + "$(cat /etc/passwd)" + " done"
CEL evaluates this to the string echo $(cat /etc/passwd) done. This string is then executed as:
sh -c 'echo $(cat /etc/passwd) done'
The $(...) command substitution executes cat /etc/passwd. Similar issues exist with &, |, ;.
Relevant Code
src/domain/expressions/model_resolver.ts lines 775–782:
const escapedValue = secretValue
.replace(/\\/g, "\\\\")
.replace(/"/g, '\\"')
.replace(/'/g, "\\'")
.replace(/`/g, "\\`")
.replace(/\n/g, "\\n")
.replace(/\r/g, "\\r")
.replace(/\t/g, "\\t");$ is not escaped.
Mitigating Factors
- This requires the user to store a value in their own vault and write a CEL expression that injects it unquoted into a shell command. It is within the user's own trust domain.
- The vault is local and under the user's control.
- No remote attacker can influence vault contents without already having local write access.
However, this is a real foot-gun: users who write parameterised shell commands driven by vault secrets have no indication that special shell characters in secret values will be interpreted by the shell.
Recommended Fix
Add $ to the escaping chain in resolveVaultExpressions():
.replace(/\$/g, "\\$")Add a test case: store a secret value containing $(echo injected) and verify it renders literally in shell output rather than being executed.
Also add documentation that vault values injected into shell run fields via CEL string concatenation are escaped for shell safety, so users understand the contract.
References
src/domain/expressions/model_resolver.ts—resolveVaultExpressions()src/domain/models/command/shell/shell_model.ts—sh -c args.run- Related fix: fix: escape single quotes and backticks in vault secret values #407 (added
'and backtick escaping to CEL layer, but shell metacharacters not addressed)