gateway config.get leaks secrets into session transcript JSONL
Summary
When the gateway tool's config.get action is invoked during a conversation, the full configuration (including plaintext API keys, tokens, and credentials) is returned as a toolResult and persisted verbatim into the session transcript file (~/.openclaw/agents/<agentId>/sessions/*.jsonl).
This means any secret stored in openclaw.json — such as skills.entries.*.apiKey, gateway.auth.token, or provider credentials — ends up in plaintext on disk in session files, which may have weaker access controls than the config file itself.
Reproduction
- In any conversation, trigger a
config.get call (e.g., ask the agent to check its config, or invoke it via a skill that reads config).
- Inspect the corresponding session JSONL:
grep -r "AIzaSy\|sk-\|xoxb-\|ghp_" ~/.openclaw/agents/*/sessions/*.jsonl
- Observe that API keys from config are stored in plaintext inside
toolResult entries.
Evidence
Using GardaClaw session forensics scanner on a real deployment:
- 64 hits for Google API keys (
skills.entries.goplaces.apiKey) — all originating from gateway config.get toolResult
- The same key appeared 64 times across multiple config reads in a single session file
- The key was
AIzaSy... (Google Places API key configured in skills.entries)
Root cause trace
User/agent invokes: gateway(action="config.get")
→ Gateway returns full openclaw.json as toolResult
→ Session engine persists toolResult to JSONL (no redaction)
→ Secrets now live in ~/.openclaw/agents/*/sessions/*.jsonl
Impact
- Credential exposure: Anyone with read access to session files can extract all secrets from config. Session files are typically
644 (more permissive than the config file at 600).
- Backup/sync leakage: Session files may be backed up (Time Machine, cloud sync, git) without the user realizing they contain secrets.
- Accumulation: Each
config.get call creates another copy. Over time, secrets are duplicated dozens of times across session files.
- Existing redaction doesn't help:
logging.redactSensitive: "tools" only affects log output, not session transcript persistence.
Suggested Fix
Option A: Redact known secret fields in config.get response (recommended)
Before returning the config as a toolResult, mask fields that are known to contain secrets:
gateway.auth.token → "gw-***"
gateway.auth.password → "***"
gateway.remote.token → "***"
skills.entries.*.apiKey → "AIza***"
channels.*.token → "***"
channels.*.tokenFile → (keep, it's a path not a secret)
A simple approach: walk the config object and mask any key matching /token|apiKey|password|secret|credential/i where the value is a string.
Option B: Redact toolResults before JSONL persistence
Apply the same redactSensitive patterns used for logging to session transcript writes. This would protect against all tools leaking secrets, not just config.get.
Option C: Both A + B
Redact at the source (config.get) and add a redaction layer to session persistence. Defense in depth.
Additional Context
openclaw security audit does not check for this issue
- Session JSONL files can grow large and are rarely reviewed by users
- This was discovered during development of GardaClaw, a security scanning skill for OpenClaw
Environment
- OpenClaw 2026.2.6
- macOS (arm64)
- Model: Claude Opus 4.6
gateway config.getleaks secrets into session transcript JSONLSummary
When the
gatewaytool'sconfig.getaction is invoked during a conversation, the full configuration (including plaintext API keys, tokens, and credentials) is returned as atoolResultand persisted verbatim into the session transcript file (~/.openclaw/agents/<agentId>/sessions/*.jsonl).This means any secret stored in
openclaw.json— such asskills.entries.*.apiKey,gateway.auth.token, or provider credentials — ends up in plaintext on disk in session files, which may have weaker access controls than the config file itself.Reproduction
config.getcall (e.g., ask the agent to check its config, or invoke it via a skill that reads config).toolResultentries.Evidence
Using GardaClaw session forensics scanner on a real deployment:
skills.entries.goplaces.apiKey) — all originating fromgateway config.gettoolResultAIzaSy...(Google Places API key configured inskills.entries)Root cause trace
Impact
644(more permissive than the config file at600).config.getcall creates another copy. Over time, secrets are duplicated dozens of times across session files.logging.redactSensitive: "tools"only affects log output, not session transcript persistence.Suggested Fix
Option A: Redact known secret fields in
config.getresponse (recommended)Before returning the config as a toolResult, mask fields that are known to contain secrets:
A simple approach: walk the config object and mask any key matching
/token|apiKey|password|secret|credential/iwhere the value is a string.Option B: Redact toolResults before JSONL persistence
Apply the same
redactSensitivepatterns used for logging to session transcript writes. This would protect against all tools leaking secrets, not justconfig.get.Option C: Both A + B
Redact at the source (config.get) and add a redaction layer to session persistence. Defense in depth.
Additional Context
openclaw security auditdoes not check for this issueEnvironment