Skip to content

Bug: agents.defaults.heartbeat.to corrupts deliveryContext, causing private messages to leak to group with different content #65847

@smallmj

Description

@smallmj

Summary

When agents.defaults.heartbeat.to is configured, all outgoing messages (including normal replies to user DMs) get incorrectly routed to the heartbeat target channel. Moreover, the content sent to the wrong channel is different from the content sent to the correct channel — as if two independent LLM generations occurred.

This is a privacy breach: private chat responses are leaked to a group/channel, and the leaked content may not even match what the user receives.

Configuration

{
  "agents": {
    "defaults": {
      "heartbeat": {
        "every": "30m",
        "activeHours": { "start": "08:00", "end": "22:00" },
        "target": "feishu",
        "to": "oc_8d6a0a64d5d4bb05a9f19c707c03ca6a"
      }
    }
  }
}

Observed Behavior

  1. User sends a DM to the agent (main)
  2. Agent generates a response intended for the DM
  3. The response appears in the heartbeat target group (oc_8d6a0a64d5d4bb05a9f19c707c03ca6a) with content A
  4. The user receives a DIFFERENT response with content B in the private chat

Or, in some cases:

  • The DM reply goes to the group
  • The heartbeat reply goes to the DM
  • Both contents are different

It appears that the routing context (deliveryContext.to) is being overwritten globally by the heartbeat configuration, and the message generation is triggered twice (once for each destination) with different outputs.

Related Issues

This is similar to but distinct from:

Root Cause Hypothesis

When agents.defaults.heartbeat.to is set, the heartbeat's routing target is being incorrectly applied to the session's deliveryContext as a side effect. Since OpenClaw uses deliveryContext.to to determine where to send outgoing messages, all messages (not just heartbeat) get routed to the heartbeat target.

Furthermore, the system seems to queue the message for both destinations (original and heartbeat target), generating two independent LLM responses. This explains the content divergence.

Workaround (Validated ✅)

Move the heartbeat configuration from agents.defaults to the specific agent that needs it:

{
  "agents": {
    "defaults": {
      // Remove heartbeat from here
    },
    "list": [
      {
        "id": "main",
        // ...
        "heartbeat": {
          "every": "30m",
          "activeHours": { "start": "08:00", "end": "22:00" },
          "target": "feishu",
          "to": "oc_8d6a0a64d5d4bb05a9f19c707c03ca6a"
        }
      }
    ]
  }
}

Validation results (after Gateway restart):

  • ✅ Private chat replies go to the correct private chat (deliveryContext.to remains user:ou_xxx)
  • ✅ Heartbeat messages still go to the target group (to be confirmed on next heartbeat tick)
  • ✅ No duplicate messages observed in testing
  • ✅ Session count remains normal (1 active session, no extra ghost sessions)

Test method:

  1. Applied configuration change (removed heartbeat from defaults, added to main)
  2. Restarted Gateway (openclaw gateway restart)
  3. Sent test DM to agent
  4. Verified deliveryContext.to in active session points to DM, not group
  5. Checked logs: only one feishu_im_user_message: send entry for the test message
  6. No evidence of duplicate routing

Note: This workaround is validated for single-agent setups. Multi-agent with different heartbeat targets needs further testing.

Impact & Severity

  • Privacy violation: Private conversations leaked to group channels
  • Data integrity: Users receive different content than what was "sent"
  • Trust: Undermines confidence in message delivery
  • Potential compliance risk: Depending on data sensitivity

OpenClaw Version

2026.4.10 (from openclaw.json meta.lastTouchedVersion)

Request

  1. Fix the routing isolation bug in agents.defaults.heartbeat handling.
  2. Document that heartbeat should be configured per-agent if routing isolation is required, or deprecate agents.defaults.heartbeat.
  3. Consider heartbeat session separation as proposed in [Bug]: Heartbeat set to reply to Telegram group gets mixed up with direct chat #28639 (run heartbeats in isolated sub-sessions that don't share delivery context).
  4. Release a patch version, as this is a high-severity bug.

Workaround Status: ✅ Validated — Configuration change applied, Gateway restarted, routing verified correct in production. Heartbeat functionality preserved. Multi-agent scenarios untested.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    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