Skip to content

Discord leaks internal tool-call traces (NO_REPLY, commentary, to=functions) to channel #44905

@ychi6567-glitch

Description

@ychi6567-glitch

Summary

Discord channels occasionally surface internal LLM tool-call artifacts that should never be visible to end-users. The leaked content includes:

  • NO_REPLY
  • to=functions.memory_search
  • commentary
  • Raw tool-call JSON arguments (e.g. {"query":"...","maxResults":5})
  • recipient_name / parameters envelope fields

Other channels (Telegram, WhatsApp, Signal) do not exhibit this issue.

Expected Behavior

  1. NO_REPLY should be consumed silently — never sent to any channel.
  2. commentary, to=functions.*, tool-call JSON, and other internal envelope fields should be stripped before delivery.
  3. Only natural-language content should reach end-users.

Actual Behavior

Discord intermittently delivers raw internal messages as visible chat messages in the channel.

Root Cause Analysis

Traced through the delivery pipeline in v2026.3.8:

1. Discord missing from PLAIN_TEXT_SURFACES (src/infra/outbound/sanitize-text.ts)

const PLAIN_TEXT_SURFACES = new Set([
  "whatsapp", "signal", "sms", "irc", "telegram", "imessage", "googlechat"
  // ← "discord" is absent
]);

normalizePayloadsForChannelDelivery() calls sanitizeForPlainText() only for surfaces in this set. Discord payloads skip sanitization entirely.

2. sanitizeTextContent() does not strip tool-routing traces (src/auto-reply/extract-text.ts)

function sanitizeTextContent(text) {
  return stripThinkingTagsFromText(stripDowngradedToolCallText(stripMinimaxToolCallXml(text)));
}

This strips thinking tags and Minimax XML, but does not catch:

  • NO_REPLY
  • to=functions.*
  • commentary
  • Bare JSON tool arguments

3. sendDiscordText() has no pre-send filter (src/infra/send/discord.ts)

The Discord send path serializes and posts the text chunk directly — no final sanitization gate.

4. NO_REPLY suppression has a gap (src/infra/outbound/normalize.ts)

In normalizeReplyPayloadsForDelivery, silent payloads are only suppressed when mergedMedia.length === 0. Payloads with media attached can pass through with NO_REPLY still in the text.

High-Probability Trigger Scenarios

  • Inter-session / cross-agent message relay
  • Subagent completion auto-forwarding
  • Intermediate tool-call messages during multi-step reasoning
  • NO_REPLY return branches

Suggested Fix

Add a universal outbound sanitizer in normalizePayloadsForChannelDelivery (or equivalent) that runs for all channels, not just plain-text surfaces:

const INTERNAL_TRACE_RE = /^(?:NO_REPLY|to=functions\.\S+.*|commentary|recipient_name|parameters)$/m;
const TOOL_JSON_RE = /^\s*\{\s*"(?:query|maxResults|tool_name|function_call|name)"\s*:/m;

function stripInternalTraces(text) {
  if (!text) return text;
  const trimmed = text.trim();
  if (trimmed === "NO_REPLY") return null;
  if (INTERNAL_TRACE_RE.test(trimmed)) return null;
  if (TOOL_JSON_RE.test(trimmed) && trimmed.length < 500) return null;
  return text
    .replace(/^NO_REPLY\s*/gm, "")
    .replace(/^to=functions\.\S+.*$/gm, "")
    .replace(/^commentary\s*$/gm, "")
    .replace(/^recipient_name\s*$/gm, "")
    .replace(/^parameters\s*$/gm, "")
    .replace(/\n{3,}/g, "\n\n")
    .trim() || null;
}

Also enhance sanitizeTextContent() to strip the same patterns at the extraction layer.

Environment

  • OpenClaw: 2026.3.8 (3caab92)
  • Platform: macOS (darwin)
  • Channels affected: Discord
  • Channels working correctly: Telegram, WhatsApp, Signal

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority user-facing bug, regression, or broken workflow.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:message-lossChannel message delivery can be lost, duplicated, or misrouted.impact:securitySecurity boundary, credential, authz, sandbox, or sensitive-data risk.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions