Bug Report: exec tool returns raw stdout/stderr to agent without secret redaction
Summary
Foreground exec results in OpenClaw are assembled directly from aggregated command output and returned to the agent without an obvious secret-redaction pass. If a command prints secrets, those secrets can enter internal tool/agent context.
Severity
High, internal secret exposure risk
Impact
- Any
exec command that prints .env contents, tokens, API keys, passwords, or other sensitive output can expose that data to the agent runtime.
- Chat surfaces may or may not separately suppress rendering, but the
exec tool path itself appears unsafe.
- This appears to affect more than one agent/runtime, not a single isolated profile.
Confirmed behavior
In the exec implementation, foreground output is returned via logic equivalent to:
function buildExecForegroundResult(params) {
const warningText = params.warningText?.trim() ? `${warningText}\n\n` : "";
if (params.outcome.status === "failed") return failedTextResult(`${warningText}${params.outcome.reason}`, {
status: "failed",
exitCode: params.outcome.exitCode ?? null,
durationMs: params.outcome.durationMs,
aggregated: params.outcome.aggregated,
timedOut: params.outcome.timedOut,
cwd: params.cwd
});
return textResult(`${warningText}${params.outcome.aggregated || "(no output)"}`, {
status: "completed",
exitCode: params.outcome.exitCode,
durationMs: params.outcome.durationMs,
aggregated: params.outcome.aggregated,
cwd: params.cwd
});
}
And this is used directly after process completion:
run.promise.then((outcome) => {
...
resolve(buildExecForegroundResult({
outcome,
cwd: run.session.cwd,
warningText: getWarningText()
}));
})
This means params.outcome.aggregated is passed straight into the tool result text.
Related files traced
- Tool wrapper:
- Exec implementation:
- Upstream exec runtime:
dist/bash-tools.exec-runtime-*.js
What is not the issue
${SECRET} indirection in config is working as expected.
EnvironmentFile=... rendering is not itself the leak.
- There is env sanitization for process env overrides, but that only controls what env is passed into the command, not what the command prints back out.
Evidence from code review
I found sanitization/redaction paths for:
- config snapshots
- logs
- chat history
- exec approval display text
I did not find a dedicated secret-redaction pass for generic exec stdout/stderr before tool result delivery.
Reproduction idea
Run a command that prints a secret-bearing env file, for example:
cat /path/to/.env
grep TOKEN /path/to/.env
Observed behavior:
- output is incorporated into the
exec tool result returned to the agent
Expected behavior:
- either block obviously sensitive file reads, or
- redact secret-looking values before tool result delivery, or
- require explicit opt-in to reveal raw secret-bearing stdout
Recommended fix
Best fix points:
- Primary: redact secrets before
buildExecForegroundResult(...) emits params.outcome.aggregated
- Also recommended: redact at the lower runtime layer when constructing
outcome.aggregated
Suggested protections
- redact env-style assignments like:
KEY=value
- especially keys matching
TOKEN, SECRET, PASSWORD, API_KEY, AUTH, PAT
- redact known secret formats:
- bot tokens
- provider API keys
- bearer tokens
- hex secrets
- optionally hard-block raw reads of common secret files:
.env
- generated env files
- credential stores
Real-world consequence seen
A diagnostic env-file read produced raw secret-bearing stdout into internal tool context during live troubleshooting. User-facing chat may have stayed clean, but the internal exposure path is confirmed and should be treated as a security bug.
Bug Report:
exectool returns raw stdout/stderr to agent without secret redactionSummary
Foreground
execresults in OpenClaw are assembled directly from aggregated command output and returned to the agent without an obvious secret-redaction pass. If a command prints secrets, those secrets can enter internal tool/agent context.Severity
High, internal secret exposure risk
Impact
execcommand that prints.envcontents, tokens, API keys, passwords, or other sensitive output can expose that data to the agent runtime.exectool path itself appears unsafe.Confirmed behavior
In the exec implementation, foreground output is returned via logic equivalent to:
And this is used directly after process completion:
This means
params.outcome.aggregatedis passed straight into the tool result text.Related files traced
dist/pi-tools-*.jsdist/bash-tools-*.jsdist/bash-tools.exec-runtime-*.jsWhat is not the issue
${SECRET}indirection in config is working as expected.EnvironmentFile=...rendering is not itself the leak.Evidence from code review
I found sanitization/redaction paths for:
I did not find a dedicated secret-redaction pass for generic
execstdout/stderr before tool result delivery.Reproduction idea
Run a command that prints a secret-bearing env file, for example:
cat /path/to/.envgrep TOKEN /path/to/.envObserved behavior:
exectool result returned to the agentExpected behavior:
Recommended fix
Best fix points:
buildExecForegroundResult(...)emitsparams.outcome.aggregatedoutcome.aggregatedSuggested protections
KEY=valueTOKEN,SECRET,PASSWORD,API_KEY,AUTH,PAT.envReal-world consequence seen
A diagnostic env-file read produced raw secret-bearing stdout into internal tool context during live troubleshooting. User-facing chat may have stayed clean, but the internal exposure path is confirmed and should be treated as a security bug.