openclaw - ✅(Solved) Fix Telegram /status leaks 'OpenClaw runtime context (internal)' + internal task completion events into user chat [1 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#58921Fetched 2026-04-08 02:31:11
View on GitHub
Comments
0
Participants
1
Timeline
3
Reactions
0
Participants
Timeline (top)
closed ×1cross-referenced ×1locked ×1

Root Cause

Summary\nRunning the native Telegram bot command /status can output the internal runtime context block and internal task completion event payloads (e.g. a subagent completion report) into the user-facing Telegram chat.\n\nThis appears to be a regression/behavior change: we never customized the status command.\n\n## Environment\n- OpenClaw: 2026.3.31 (commit 213a704)\n- OS: macOS\n- Channel: Telegram\n- Command: native /status\n\n## Expected\n/status should return a clean status summary (model, context %, gateway ok, etc.) and must not include internal runtime context blocks or child task completion payloads in user chats.\n\n## Actual\n/status intermittently prints a large block starting with:\n\n- OpenClaw runtime context (internal):\n- [Internal task completion event]\n\n…including child session key/id, task label, status, and the full "untrusted child result" content.\n\n## Impact\n- User chats get spammed with internal/debug context.\n- Potential privacy/safety issue: internal subagent outputs are surfaced to end users in a channel response.\n- Confusing UX: looks like the bot is "sending Atlas reports" when user just asked for status.\n\n## Investigation / Suspected root cause\nThe string is generated in the dist build:\n- dist/pi-embedded-*.js contains formatAgentInternalEventsForPrompt() which renders:\n - OpenClaw runtime context (internal):\n - and formats task_completion events into [Internal task completion event] blocks.\n- dist/agent-command-*.js contains prependInternalEventContext(body, events) which prepends rendered internal events to a message body.\n\nIt appears the Telegram native /status path is using a session/tool output that includes these internal events, and the internal-event prefix is being included in the final user-visible reply.\n\n## Attempted mitigations (did not resolve)\n- Disabled likely cron sources (ccc-monitor, ccc-review-check)\n- Disabled Telegram streaming / streamMode\n- Disabled hooks.internal.enabled and hooks.enabled\n- Set plugins.allow = []\n- Disabled diagnostics.enabled\n\nBehavior persists, suggesting this is in the native command/status rendering path rather than external hooks/cron/plugins.\n\n## Proposed fix\nDo not prepend/render internal task completion events for user message channels (Telegram/Discord/etc). Restrict internal runtime context to logs/dashboard or explicit opt-in debug commands only.\n\nA simple fix could gate prependInternalEventContext() (or its caller) behind a "debug" flag / internal channel check, or ensure native /status uses a sanitized status source that does not include internal event blocks.\n\n## Repro steps\n1. Configure Telegram channel + bot\n2. Run any subagent task so an internal completion event exists\n3. In Telegram, run /status\n4. Observe internal task completion event printed in chat\n

Fix Action

Fix / Workaround

Summary\nRunning the native Telegram bot command /status can output the internal runtime context block and internal task completion event payloads (e.g. a subagent completion report) into the user-facing Telegram chat.\n\nThis appears to be a regression/behavior change: we never customized the status command.\n\n## Environment\n- OpenClaw: 2026.3.31 (commit 213a704)\n- OS: macOS\n- Channel: Telegram\n- Command: native /status\n\n## Expected\n/status should return a clean status summary (model, context %, gateway ok, etc.) and must not include internal runtime context blocks or child task completion payloads in user chats.\n\n## Actual\n/status intermittently prints a large block starting with:\n\n- OpenClaw runtime context (internal):\n- [Internal task completion event]\n\n…including child session key/id, task label, status, and the full "untrusted child result" content.\n\n## Impact\n- User chats get spammed with internal/debug context.\n- Potential privacy/safety issue: internal subagent outputs are surfaced to end users in a channel response.\n- Confusing UX: looks like the bot is "sending Atlas reports" when user just asked for status.\n\n## Investigation / Suspected root cause\nThe string is generated in the dist build:\n- dist/pi-embedded-*.js contains formatAgentInternalEventsForPrompt() which renders:\n - OpenClaw runtime context (internal):\n - and formats task_completion events into [Internal task completion event] blocks.\n- dist/agent-command-*.js contains prependInternalEventContext(body, events) which prepends rendered internal events to a message body.\n\nIt appears the Telegram native /status path is using a session/tool output that includes these internal events, and the internal-event prefix is being included in the final user-visible reply.\n\n## Attempted mitigations (did not resolve)\n- Disabled likely cron sources (ccc-monitor, ccc-review-check)\n- Disabled Telegram streaming / streamMode\n- Disabled hooks.internal.enabled and hooks.enabled\n- Set plugins.allow = []\n- Disabled diagnostics.enabled\n\nBehavior persists, suggesting this is in the native command/status rendering path rather than external hooks/cron/plugins.\n\n## Proposed fix\nDo not prepend/render internal task completion events for user message channels (Telegram/Discord/etc). Restrict internal runtime context to logs/dashboard or explicit opt-in debug commands only.\n\nA simple fix could gate prependInternalEventContext() (or its caller) behind a "debug" flag / internal channel check, or ensure native /status uses a sanitized status source that does not include internal event blocks.\n\n## Repro steps\n1. Configure Telegram channel + bot\n2. Run any subagent task so an internal completion event exists\n3. In Telegram, run /status\n4. Observe internal task completion event printed in chat\n

PR fix notes

PR #59649: fix(agent): close remaining internal-context leak paths

Description (problem / solution / changelog)

Summary

Describe the problem and fix in 2–5 bullets:

If this PR fixes a plugin beta-release blocker, title it fix(<plugin-id>): beta blocker - <summary> and link the matching Beta blocker: <plugin-name> - <summary> issue labeled beta-blocker. Contributors cannot label PRs, so the title is the PR-side signal for maintainers and automation.

  • Problem: several adjacent user-facing task/status/followup surfaces still rendered raw internal runtime context, task-completion metadata, or raw exec approval followup text even after /status stale-row hardening.
  • Why it matters: internal runtime context and raw exec-denial/completion details can leak into visible chat surfaces across command/status flows, which is both noisy and a privacy/safety problem.
  • What changed: this PR centralizes task-status sanitization across /tasks, /subagents info, /acp status, task notification formatting, and run labels; strips legacy unmarked internal blocks even when embedded; and sanitizes or suppresses no-session exec approval followups instead of raw-sending them.
  • What did NOT change (scope boundary): this PR does not change task lifecycle semantics, approval routing/auth, session/task linkage, or broader streamed-reply sanitization outside these user-facing task/followup surfaces.

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 #58921
  • Related #44528, #39032, #59025, #51149, #58748, #58783, #58810
  • This PR fixes a bug or regression

Root Cause / Regression History (if applicable)

For bug fixes or regressions, explain why this happened, not just what changed. Otherwise write N/A. If the cause is unclear, write Unknown.

  • Root cause: user-facing task, command, and followup surfaces were formatting raw progressSummary, error, terminalSummary, runtime status text, and exec followup result text directly, while sanitization only existed in narrower /status-adjacent or final-reply paths.
  • Missing detection / guardrail: there was no regression coverage for contaminated task records and followup payloads across /tasks, /subagents info, /acp status, task notification formatting, run-label formatting, and no-session exec followups.
  • Prior context (git blame, prior PR, issue, or refactor if known): #58810 fixed stale completed task rows in status cards but did not sanitize neighboring task/followup surfaces; legacy internal-context stripping also only handled the start-of-string case before this change.
  • Why this regressed now: this appears to be a pre-existing leak family rather than a single fresh regression; partial hardening covered /status first, which left adjacent user-facing surfaces still leaking the same class of internals.
  • If unknown, what was ruled out: ruled out a stale-row-only explanation by reproducing/locking leaks in /tasks, /subagents info, /acp status, blocked task messages, run labels, and no-session exec followups with contaminated payloads.

Regression Test Plan (if applicable)

For bug fixes or regressions, name the smallest reliable test coverage that should have caught this. Otherwise write N/A.

  • 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/tasks/task-status.test.ts
    • src/tasks/task-executor-policy.test.ts
    • src/agents/pi-embedded-helpers.sanitizeuserfacingtext.test.ts
    • src/agents/bash-tools.exec-approval-followup.test.ts
    • src/auto-reply/reply/commands-status.test.ts
    • src/auto-reply/reply/commands-tasks.test.ts
    • src/auto-reply/reply/commands-acp.test.ts
    • src/auto-reply/reply/commands.test.ts
    • src/auto-reply/reply/reply-plumbing.test.ts
  • Scenario the test should lock in: contaminated legacy internal blocks and raw Exec denied (...) / Exec finished (...) payloads never reach /tasks, /status, /subagents info, /acp status, task notifications, formatted run labels, or no-session followup delivery as raw internal text.
  • Why this is the smallest reliable guardrail: these failures occur in formatter/command seams before channel delivery, so focused unit + command-surface tests catch the leak without requiring a live provider or channel integration.
  • Existing test that already covers this (if any): existing /status coverage already guarded the stale-row/status-card path; this PR extends coverage to the adjacent surfaces that were still leaking.
  • If no new test is added, why not: N/A (new tests added)

User-visible / Behavior Changes

List user-visible changes (including defaults/config). If none, write None.

  • /tasks, /status, /subagents info, and /acp status no longer expose internal runtime-context blocks or raw exec approval denial text from contaminated task/runtime records.
  • Blocked/failure task followups now present sanitized user-safe text instead of raw internal metadata.
  • No-session exec approval followups now suppress denied raw text and sanitize completed/failed raw summaries before direct delivery.

Diagram (if applicable)

For UI changes or non-trivial logic flows, include a small ASCII diagram reviewers can scan quickly. Otherwise write N/A.

Before:
[task/error/followup payload]
  -> [surface-specific formatter]
  -> [raw internal block / exec metadata reaches user-visible text]

After:
[task/error/followup payload]
  -> [shared sanitizeTaskStatusText / sanitizeUserFacingText]
  -> [surface formatter]
  -> [user-safe status/update text]

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: Ubuntu Linux (ARM64 EC2 host)
  • Runtime/container: local repo checkout with Node/pnpm + Vitest
  • Model/provider: N/A (fixture-based sanitization paths; no live provider call required for verification)
  • Integration/channel (if any): simulated Telegram/Discord/Slack command and followup paths in tests
  • Relevant config (redacted): default repo test configuration; no config/env changes

Steps

  1. Create or load a task/followup payload containing a legacy OpenClaw runtime context (internal) block and/or raw Exec denied (...) / Exec finished (...) text.
  2. Render that payload through /tasks, /status, /subagents info, /acp status, task notification formatting, run-label formatting, or no-session exec approval followup delivery.
  3. Compare visible output before and after this PR.

Expected

  • Only sanitized, user-safe text is shown; embedded legacy internal blocks are removed and raw exec approval internals are redacted or suppressed.

Actual

  • Before this PR, raw internal runtime text and raw exec approval followup text could surface in those user-facing outputs.

Evidence

Attach at least one:

  • Failing test/log before + passing after

  • Trace/log snippets

  • Screenshot/recording

  • Perf numbers (if relevant)

  • Before (targeted combined run while gaps remained): failures reproduced in commands.test.ts, commands-acp.test.ts, commands-status.test.ts, commands-tasks.test.ts, reply-plumbing.test.ts, and task-status.test.ts on leaked internal-context / raw exec-detail cases.

  • After (post-fix sharded verification): touched-path suites passed 9 test files / 249 tests, and pnpm check passed at commit time.

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: reviewed the rebased diff against upstream/main; ran pnpm check; ran focused post-rebase Vitest shards covering task status, task executor policy, /tasks, /status, /subagents info, /acp status, reply plumbing, and exec approval followups.
  • Edge cases checked: embedded legacy blocks with surrounding clean text preserved; ordinary mentions of internal marker strings remain intact; blocked task summaries carrying raw Exec denied (...); no-session exec followups with denied, finished-with-output, and finished-without-output cases; run-label sanitization fallback.
  • What you did not verify: full GitHub CI matrix; live manual Telegram/Discord/Slack end-to-end runs against a deployed gateway.

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.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

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

Risks and Mitigations

List only real risks for this PR. Add/remove entries as needed. If none, write None.

  • Risk: over-sanitizing legitimate user-visible text that resembles internal block headers or exec-denial text.
  • Mitigation: legacy stripping requires the canonical runtime header + event shape, tests preserve ordinary mentions, and exec-denial rewriting only applies in error/followup contexts.
  • Risk: no-session followups may now collapse raw completion metadata to a generic summary when no safe user-visible body remains.
  • Mitigation: successful visible output is preserved whenever safe body text exists; the generic fallback is only used when the remaining text is internal/noisy metadata.

Changed files

  • src/agents/bash-tools.exec-approval-followup.test.ts (modified, +55/-3)
  • src/agents/bash-tools.exec-approval-followup.ts (modified, +60/-3)
  • src/agents/internal-events.ts (modified, +40/-8)
  • src/agents/pi-embedded-helpers.sanitizeuserfacingtext.test.ts (modified, +120/-0)
  • src/agents/pi-embedded-helpers/errors.ts (modified, +195/-1)
  • src/auto-reply/reply/commands-acp.test.ts (modified, +87/-0)
  • src/auto-reply/reply/commands-acp/runtime-options.ts (modified, +19/-10)
  • src/auto-reply/reply/commands-status.test.ts (modified, +28/-0)
  • src/auto-reply/reply/commands-subagents/action-info.ts (modified, +13/-5)
  • src/auto-reply/reply/commands-tasks.test.ts (modified, +30/-0)
  • src/auto-reply/reply/commands-tasks.ts (modified, +7/-6)
  • src/auto-reply/reply/commands.test.ts (modified, +61/-0)
  • src/auto-reply/reply/reply-plumbing.test.ts (modified, +15/-0)
  • src/auto-reply/reply/subagents-utils.ts (modified, +2/-1)
  • src/tasks/task-executor-policy.test.ts (modified, +57/-0)
  • src/tasks/task-executor-policy.ts (modified, +23/-12)
  • src/tasks/task-status.test.ts (modified, +70/-0)
  • src/tasks/task-status.ts (modified, +71/-11)
RAW_BUFFERClick to expand / collapse

Summary\nRunning the native Telegram bot command /status can output the internal runtime context block and internal task completion event payloads (e.g. a subagent completion report) into the user-facing Telegram chat.\n\nThis appears to be a regression/behavior change: we never customized the status command.\n\n## Environment\n- OpenClaw: 2026.3.31 (commit 213a704)\n- OS: macOS\n- Channel: Telegram\n- Command: native /status\n\n## Expected\n/status should return a clean status summary (model, context %, gateway ok, etc.) and must not include internal runtime context blocks or child task completion payloads in user chats.\n\n## Actual\n/status intermittently prints a large block starting with:\n\n- OpenClaw runtime context (internal):\n- [Internal task completion event]\n\n…including child session key/id, task label, status, and the full "untrusted child result" content.\n\n## Impact\n- User chats get spammed with internal/debug context.\n- Potential privacy/safety issue: internal subagent outputs are surfaced to end users in a channel response.\n- Confusing UX: looks like the bot is "sending Atlas reports" when user just asked for status.\n\n## Investigation / Suspected root cause\nThe string is generated in the dist build:\n- dist/pi-embedded-*.js contains formatAgentInternalEventsForPrompt() which renders:\n - OpenClaw runtime context (internal):\n - and formats task_completion events into [Internal task completion event] blocks.\n- dist/agent-command-*.js contains prependInternalEventContext(body, events) which prepends rendered internal events to a message body.\n\nIt appears the Telegram native /status path is using a session/tool output that includes these internal events, and the internal-event prefix is being included in the final user-visible reply.\n\n## Attempted mitigations (did not resolve)\n- Disabled likely cron sources (ccc-monitor, ccc-review-check)\n- Disabled Telegram streaming / streamMode\n- Disabled hooks.internal.enabled and hooks.enabled\n- Set plugins.allow = []\n- Disabled diagnostics.enabled\n\nBehavior persists, suggesting this is in the native command/status rendering path rather than external hooks/cron/plugins.\n\n## Proposed fix\nDo not prepend/render internal task completion events for user message channels (Telegram/Discord/etc). Restrict internal runtime context to logs/dashboard or explicit opt-in debug commands only.\n\nA simple fix could gate prependInternalEventContext() (or its caller) behind a "debug" flag / internal channel check, or ensure native /status uses a sanitized status source that does not include internal event blocks.\n\n## Repro steps\n1. Configure Telegram channel + bot\n2. Run any subagent task so an internal completion event exists\n3. In Telegram, run /status\n4. Observe internal task completion event printed in chat\n

extent analysis

TL;DR

The issue can be fixed by modifying the prependInternalEventContext() function to exclude internal events for user message channels.

Guidance

  • Review the formatAgentInternalEventsForPrompt() function in dist/pi-embedded-*.js to understand how internal events are rendered.
  • Modify the prependInternalEventContext() function in dist/agent-command-*.js to gate its behavior behind a "debug" flag or internal channel check.
  • Ensure the native /status command uses a sanitized status source that does not include internal event blocks.
  • Verify the fix by running the repro steps and checking that internal task completion events are no longer printed in the Telegram chat.

Example

// Example modification to prependInternalEventContext()
function prependInternalEventContext(body, events, isDebugChannel) {
  if (!isDebugChannel) {
    return body; // exclude internal events for non-debug channels
  }
  // existing implementation
}

Notes

The proposed fix assumes that the issue is caused by the prependInternalEventContext() function prepending internal events to the message body. However, the root cause may be more complex, and additional debugging may be necessary.

Recommendation

Apply a workaround by modifying the prependInternalEventContext() function to exclude internal events for user message channels, as this is a targeted fix that addresses the specific issue without introducing unnecessary changes.

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…

Still need to ship something?

×6

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

Back to top recommendations

TRENDING