openclaw - ✅(Solved) Fix [Bug]: tools.exec.security corrupted by plugin init logs — hot-reload concatenates plugin output into config value [3 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#64821Fetched 2026-04-12 13:26:34
View on GitHub
Comments
0
Participants
1
Timeline
4
Reactions
0
Participants
Timeline (top)
labeled ×3cross-referenced ×1

During normal gateway operation, the config values tools.exec.security and tools.exec.strictInlineEval are silently corrupted by the hot-reload mechanism. The correct values ("full" and false) are replaced with a concatenation of plugin initialization log output followed by the correct terminal value.

Root Cause

During normal gateway operation, the config values tools.exec.security and tools.exec.strictInlineEval are silently corrupted by the hot-reload mechanism. The correct values ("full" and false) are replaced with a concatenation of plugin initialization log output followed by the correct terminal value.

Fix Action

Fix / Workaround

Workaround: openclaw-ops update-check bridge auto-detects and corrects, but gateway restart is required to apply.

PR fix notes

PR #64834: fix(secrets): extract last non-empty stdout line for single-value exec secret refs

Description (problem / solution / changelog)

Closes #64821

Changed files

  • extensions/memory-core/src/dreaming-narrative.ts (modified, +2/-0)
  • src/gateway/server-methods/chat.directive-tags.test.ts (modified, +31/-0)
  • src/gateway/server-methods/chat.ts (modified, +3/-0)
  • src/secrets/resolve.test.ts (modified, +16/-0)
  • src/secrets/resolve.ts (modified, +9/-1)

PR #66413: fix(secrets): extract last non-empty stdout line for single-value exec secret refs

Description (problem / solution / changelog)

Summary

  • Problem: During config hot-reload, plugin init logs (stdout) are concatenated into exec secret provider output. When jsonOnly: false and a single ref ID is resolved, the full stdout (logs + actual value) is returned as the config value, corrupting fields like tools.exec.security and tools.exec.strictInlineEval.
  • Why it matters: Security-critical config values are silently corrupted — tools.exec.security becomes a long string starting with plugin logs instead of "full", weakening the gateway's exec security posture without any error or warning.
  • What changed: In parseExecValues, when falling back to raw stdout for a single non-JSON exec ref, extract the last non-empty line instead of the full trimmed stdout. Plugin log lines are prepended to stdout; the actual value is always the final line.
  • What did NOT change (scope boundary): JSON exec providers, multi-ref exec providers, file/env providers, and the hot-reload mechanism itself are untouched. The runExecResolver spawn logic is unchanged.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #64821
  • Related #64834 (same fix, closed due to author PR limit)
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: parseExecValues returns the full trimmed stdout as the secret value when JSON parsing fails for a single-ref, non-JSON exec provider. Plugin init logs written to the gateway process stdout during hot-reload are captured by the same child_process.spawn pipe and prepended to the actual value.
  • Missing detection / guardrail: No separation between plugin init output and exec provider stdout capture. No validation that resolved config values match their expected schema (e.g. tools.exec.security should be an enum, not a free-form string).
  • Contributing context (if known): Only surfaces after ~48h when a config hot-reload triggers plugin re-initialization concurrently with secret resolution. The plugin logs from lossless-claw and openclaw-tavily are buffered and flushed into the stdout stream read by the exec resolver.

Regression Test Plan (if applicable)

  • Coverage level that should catch this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/secrets/resolve.test.ts
  • Scenario the test should lock in: When an exec provider returns stdout with preamble lines followed by the actual value on the last line, parseExecValues should return only the last non-empty line as the resolved value.
  • Why this is the smallest reliable guardrail: The corruption happens entirely within parseExecValues; a unit test with multi-line stdout input is sufficient.
  • If no new test is added, why not: Test can be added as follow-up; the fix is a 5-line change in a single function with clear before/after behavior.

User-visible / Behavior Changes

None. Config values that were being silently corrupted will now resolve to their correct values. No new config keys, no changed defaults.

Diagram (if applicable)

Before:
[hot-reload] -> [plugin init logs to stdout] -> [exec provider stdout capture]
  -> stdout = "[plugins]...logs...\nfull"
  -> parseExecValues returns "[plugins]...logs...\nfull" (corrupted)

After:
[hot-reload] -> [plugin init logs to stdout] -> [exec provider stdout capture]
  -> stdout = "[plugins]...logs...\nfull"
  -> parseExecValues returns "full" (last non-empty line)

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? Yes
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No
  • Explanation: The change narrows which portion of exec stdout is used as the resolved secret value. This is strictly more correct — it prevents log pollution from being treated as part of a secret/config value. No new attack surface is introduced.

Repro + Verification

Environment

  • OS: Linux 6.8.0 (Ubuntu/Debian)
  • Runtime/container: Node, systemd-managed gateway
  • Model/provider: minimax/minimax-m2.7 via OpenRouter
  • Integration/channel: N/A
  • Relevant config: plugins: lossless-claw, [email protected]; tools.exec.security: "full"; tools.exec.strictInlineEval: false

Steps

  1. Run OpenClaw gateway with plugins lossless-claw and openclaw-tavily enabled
  2. Wait for normal operation (~48h) or trigger config hot-reload via openclaw config set
  3. Inspect tools.exec.security value at runtime

Expected

  • tools.exec.security = "full"
  • tools.exec.strictInlineEval = false

Actual (before fix)

  • tools.exec.security = "[plugins][lcm]Plugin loaded...full"
  • tools.exec.strictInlineEval = "[plugins][lcm]Plugin loaded...false"

Evidence

  • Corruption pattern from issue #64821 confirms the actual value is always the last token in the corrupted string
  • Workaround (openclaw-ops update-check bridge) auto-detects and corrects, confirming the correct value is recoverable from the tail of the string

Human Verification (required)

  • Verified scenarios: Read through parseExecValues control flow; confirmed single-line stdout is unaffected (lastLine === trimmed); confirmed multi-line stdout with log preamble correctly extracts final value.
  • Edge cases checked: Empty stdout (existing guard returns error before reaching this code), single-line stdout (no behavior change), JSON stdout (parsed before reaching the catch block).
  • What I did not verify: Runtime reproduction on a live gateway with the specific plugin combination. PEM/multiline secret payloads in non-JSON single-ref mode (documented as jsonOnly: true recommended path).

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Risks and Mitigations

  • Risk: Multi-line non-JSON exec provider output (e.g. raw PEM key) would be truncated to the last line.
    • Mitigation: This only applies when jsonOnly: false with a single ref. The docs recommend jsonOnly: true for structured payloads. PEM keys should use file providers or JSON-wrapped exec providers. This matches the pre-existing contract where non-JSON single-ref mode expects a single-value output, not a multi-line payload.

Changed files

  • extensions/slack/src/monitor/provider.gateway-crash.test.ts (added, +44/-0)
  • extensions/slack/src/monitor/provider.ts (modified, +8/-6)
  • src/secrets/resolve.test.ts (modified, +26/-0)
  • src/secrets/resolve.ts (modified, +15/-4)
  • ui/src/ui/app-render.helpers.ts (modified, +1/-1)

PR #68384: fix(secrets): reject noisy plain exec stdout

Description (problem / solution / changelog)

Summary

  • Problem: the exec secret resolver accepted any non-JSON single-value stdout verbatim when jsonOnly: false, including plugin/log noise followed by the intended scalar.
  • Why it matters: if an exec-backed resolver emits machine output plus incidental logs, OpenClaw can treat the entire polluted stdout as the configured value.
  • What changed: the plain-text fallback now only accepts exactly one non-empty line; noisy multi-line stdout must be emitted as JSON or it is rejected.
  • What did NOT change (scope boundary): this PR does not alter JSON exec-provider handling, config writeback behavior, or gateway hot-reload semantics.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Related #64821
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: parseExecValues() in src/secrets/resolve.ts trimmed full stdout and, for jsonOnly: false single-id exec providers, returned the entire non-JSON payload as the resolved value.
  • Missing detection / guardrail: there was no regression test covering noisy stdout before the intended scalar output.
  • Contributing context (if known): a local debug reproduction confirmed that plugin-style log noise can reach this fallback path and be accepted verbatim.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/secrets/resolve.test.ts
  • Scenario the test should lock in: a non-JSON single-value exec provider that prints plugin/log noise plus the intended value on separate lines is rejected instead of folded into the resolved scalar.
  • Why this is the smallest reliable guardrail: the bug is isolated to the plain-text fallback parser, so a focused unit test exercises the exact trust boundary without unrelated gateway setup.
  • Existing test that already covers this (if any): supports non-JSON single-value exec output when jsonOnly is false continues to cover the valid single-line case.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

  • Exec providers using jsonOnly: false must emit either JSON or exactly one non-empty plain-text line.
  • Multi-line noisy stdout is now rejected with an explicit error instead of being silently accepted as the resolved value.

Diagram (if applicable)

Before:
[exec provider stdout: log line + plain value] -> [non-JSON single-id fallback] -> [entire polluted stdout accepted]

After:
[exec provider stdout: log line + plain value] -> [non-JSON single-id fallback] -> [explicit noisy-stdout error]

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (Yes)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)
  • If any Yes, explain risk + mitigation:
    • The change tightens secret-resolution parsing by rejecting ambiguous plain-text output; valid single-line plain output and JSON output continue to work.

Repro + Verification

Environment

  • OS: macOS local dev
  • Runtime/container: pnpm workspace tests
  • Model/provider: N/A
  • Integration/channel (if any): exec-backed secret provider
  • Relevant config (redacted): jsonOnly: false single-id exec provider

Steps

  1. Run an exec provider that prints plugin/log noise on one line and the intended plain value on the next.
  2. Resolve the provider with jsonOnly: false.

Expected

  • OpenClaw rejects noisy stdout and asks for JSON or one clean line.

Actual

  • Verified by focused regression tests and local gates.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

  • Verified scenarios: Ran targeted secret-resolver tests, pnpm check, and pnpm build.
  • Edge cases checked: valid one-line plain output still works; noisy multi-line plain output now throws.
  • What you did not verify: external third-party plugins or out-of-repo bridge workflows beyond the focused parser seam.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Mostly)
  • Config/env changes? (No)
  • Migration needed? (No)
  • If yes, exact upgrade steps:

Risks and Mitigations

  • Risk: an existing exec provider that relied on multi-line non-JSON stdout will now fail instead of being tolerated.
    • Mitigation: JSON output remains fully supported, and valid plain-text output still works when the provider emits one clean line.

Changed files

  • src/secrets/resolve.test.ts (modified, +18/-0)
  • src/secrets/resolve.ts (modified, +12/-1)
RAW_BUFFERClick to expand / collapse

Bug type

Crash (process/app exits or hangs)

Beta release blocker

No

Summary

During normal gateway operation, the config values tools.exec.security and tools.exec.strictInlineEval are silently corrupted by the hot-reload mechanism. The correct values ("full" and false) are replaced with a concatenation of plugin initialization log output followed by the correct terminal value.

Steps to reproduce

  1. Run OpenClaw gateway with plugins lossless-claw and openclaw-tavily enabled
  2. Wait for normal gateway operation (~48h cycle observed)
  3. Trigger a config hot-reload (e.g., any config change via openclaw config set)
  4. Observe that tools.exec.security now contains the concatenated init logs

Expected behavior

tools.exec.security should always be "full" and tools.exec.strictInlineEval should always be false. The hot-reload mechanism should preserve the original config value exactly, not append buffered stdout/stderr from plugin init.

Actual behavior

tools.exec.security becomes:

'[plugins][lcm]Pluginloaded(enabled=true,db=/home/ubuntu/.openclaw/lcm.db,threshold=0.75)[plugins][lcm]Compactionsummarizationmodel:minimax/minimax-m2.7(override)[plugins]tavily:initialized(depth=advanced,maxResults=5,answer=true,rawContent=false,timeout=30s,cacheTtl=15min)full'

tools.exec.strictInlineEval becomes:

'[plugins][lcm]Pluginloaded(enabled=true,db=/home/ubuntu/.openclaw/lcm.db,threshold=0.75)[plugins][lcm]Compactionsummarizationmodel:minimax/minimax-m2.7(override)[plugins]tavily:initialized(depth=advanced,maxResults=5,answer=true,rawContent=false,timeout=30s,cacheTtl=15min)false'

Plugin init logs are concatenated directly into the config string value, followed by the correct terminal value (full/false). The string is otherwise valid but corrupted.

OpenClaw version

2026.4.8

Operating system

Linux 6.8.0 (oracle) — Ubuntu/Debian variant

Install method

npm global (npm install -g openclaw)

Model

Minimax m2.7

Provider / routing chain

• Gateway runs on foundry (systemd-managed) • Model routing: minimax/minimax-m2.7 via OpenRouter • Plugins: [email protected], lossless-claw, memory-lancedb-pro • No custom exec approvals beyond defaults

Additional provider/model setup details

No response

Logs, screenshots, and evidence

Impact and severity

No response

Additional information

Workaround: openclaw-ops update-check bridge auto-detects and corrects, but gateway restart is required to apply.

extent analysis

TL;DR

The hot-reload mechanism in OpenClaw gateway is corrupting config values by concatenating plugin initialization log output, which can be temporarily resolved by restarting the gateway after running the openclaw-ops update-check bridge.

Guidance

  • The issue seems to be related to the hot-reload mechanism not properly handling plugin initialization logs, causing config values to be corrupted.
  • To verify the issue, check the config values of tools.exec.security and tools.exec.strictInlineEval after triggering a config hot-reload.
  • A potential workaround is to use the openclaw-ops update-check bridge to auto-detect and correct the corrupted config values, and then restart the gateway to apply the changes.
  • It may be helpful to investigate the plugin initialization logs to understand why they are being concatenated into the config string values.

Example

No code snippet is provided as the issue does not imply a specific code change.

Notes

The provided workaround requires a gateway restart, which may not be ideal in all situations. Further investigation into the hot-reload mechanism and plugin initialization logs may be necessary to find a more permanent solution.

Recommendation

Apply the workaround by using the openclaw-ops update-check bridge to auto-detect and correct the corrupted config values, and then restart the gateway to apply the changes. This is a temporary solution until a more permanent fix can be found.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

tools.exec.security should always be "full" and tools.exec.strictInlineEval should always be false. The hot-reload mechanism should preserve the original config value exactly, not append buffered stdout/stderr from plugin init.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING