openclaw - ✅(Solved) Fix [Bug]: Telegram exec approvals ignore targets.accountId and fan out across all bot accounts [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#69916Fetched 2026-04-22 07:46:44
View on GitHub
Comments
0
Participants
1
Timeline
1
Reactions
0
Author
Participants
Timeline (top)
cross-referenced ×1

In a multi-agent OpenClaw deployment with multiple Telegram bot accounts, exec approval delivery ignores approvals.exec.targets[].accountId and fans out the same approval prompt to every Telegram account that can reach the target chat ID.

In our case, a single Sentry exec approval is generated once, but the same approval object is delivered into all Telegram bot threads (Sentry, Clawmantha, Jeffrey, Sri, Mrs_Doubtfire, etc.) instead of only the sentry account specified in config.

This is not an inbound routing issue and not a duplicate of the named-account DM drop fixed in #32426. It appears to be a distinct approval delivery routing bug in the same broader Telegram accountId bug family.

Root Cause

  • approval spam across every bot thread
  • operator confusion about which bot/thread is authoritative
  • users see the same security prompt 5-7 times for one action
  • makes multi-agent Telegram setups materially worse after hardening / approval enablement

Fix Action

Fix / Workaround

Workarounds attempted

  • Local config already uses a single approval target with explicit accountId
  • Removing allowFrom from the other Telegram accounts would reduce fan-out, but it would also break ordinary DM interaction with those agents
  • No safe local config workaround was found

PR fix notes

PR #69936: fix: scope exec/plugin approval delivery to configured target accountId

Description (problem / solution / changelog)

Closes #69916.

Root cause

When the exec approval forwarder runs in mode: "targets" (or "both") and the operator configures approvals.exec.targets[].accountId for a channel, the explicit forward target is passed through correctly on the forwarder path — deliverToTargets in src/infra/exec-approval-forwarder.ts threads target.accountId into deliverOutboundPayloads, which is honored by the Telegram outbound adapter.

The native approval runtime does not share that path. Each channel plugin (Telegram, Matrix, Slack, Discord, …) independently asks resolveApprovalRequestChannelAccountId (via matchesTelegramRequestAccount and friends) which channel account the incoming approval belongs to. That helper only looked at:

  1. request.request.turnSourceAccountId (when the turn source matched the channel), and
  2. the persisted session binding for the agent's session key (lastAccountId / origin.accountId).

When an exec approval request fires with no turn-source account and no session binding for the expected channel — common in multi-agent deployments where the approval is initiated internally rather than from an inbound message — the helper returned null. Every Telegram account whose allowFrom included the approver's chat id then passed the permissive branch in matchesTelegramRequestAccount, so every bot's native runtime posted its own approval prompt to the shared approver chat. The explicit approvals.exec.targets[].accountId was never consulted here even though it unambiguously identified the intended bot.

Fix

Extend resolveApprovalRequestChannelAccountId with a last-resort fallback: when turn-source and session bindings do not pin an account for the channel, consult approvals.{exec,plugin}.targets[].accountId. If exactly one account id is configured across the targets that are scoped to this channel, use it. If any target on this channel has no accountId, or if multiple target account ids disagree, the fallback returns null and the existing heuristics keep running — so we never invent a binding where operator intent is ambiguous.

This keeps the fallback strictly additive: every input shape that previously resolved a non-null account id resolves the same account id, and any config that does not set channel-scoped targets[].accountId behaves exactly as it did before.

Why this is safe

  • Runtime controls are unchanged. Telegram's allowFrom, /approve sender verification, approvals.exec.allow/deny, tools.exec.*, elevated gating, and host exec policy remain the sole authority for whether a command is allowed to run. This change only affects which channel account's native runtime opts in to render the approval prompt; it never authorizes execution.
  • No new defaults. The forwarding mode default ("session") matches the existing DEFAULT_MODE constant in src/infra/exec-approval-forwarder.ts. No schema, help text, or generated artifact changes.
  • No behavior change for existing configs. Without mode: "targets" | "both" or without per-channel targets[].accountId, the helper returns through the same branches it did before.
  • Ambiguity is explicit. Mixed / missing accountId across same-channel targets short-circuits to null, preserving the previous permissive path instead of silently choosing one account.

Tests

The regression test reproduces the fan-out from #69916 directly on shouldHandleTelegramExecApprovalRequest and asserts that with one explicit approvals.exec.targets[].accountId the matching bot is the only account whose native runtime accepts the request.

Commands run:

  • `pnpm vitest run --config test/vitest/vitest.extension-telegram.config.ts extensions/telegram/src/exec-approvals.test.ts`
  • `pnpm vitest run --config test/vitest/vitest.infra.config.ts src/infra/exec-approval-session-target.test.ts src/infra/exec-approval-forwarder.test.ts src/infra/approval-native-runtime.test.ts`
  • `pnpm vitest run --config test/vitest/vitest.infra.config.ts` (205 files, 2425 passed / 4 skipped)
  • `pnpm test:extension telegram` (100 files, 1386 passed)
  • `pnpm test:contracts` (contracts-channels + contracts-plugin, both green)
  • `node scripts/check-src-extension-import-boundary.mjs --json` → `[]`
  • `node scripts/check-sdk-package-extension-import-boundary.mjs --json` → `[]`
  • `node scripts/check-test-helper-extension-import-boundary.mjs --json` → `[]`
  • `pnpm tsgo:core` (clean; the pre-existing `extensions/qa-lab` and `extensions/qqbot` `tsgo:extensions` failures on `main` are unrelated to this change)

AI-assisted

  • AI-assisted (Cursor)
  • Fully tested (new regression test + targeted infra/telegram/contract lanes)
  • I understand what the code does

Made with Cursor

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • extensions/telegram/src/exec-approvals.test.ts (modified, +115/-0)
  • src/infra/approval-request-account-binding.ts (modified, +56/-3)

Code Example

{
  "approvals": {
    "exec": {
      "enabled": true,
      "mode": "targets",
      "targets": [
        {
          "channel": "telegram",
          "to": "6522813629",
          "accountId": "sentry"
        }
      ]
    }
  },
  "channels": {
    "telegram": {
      "accounts": {
        "default": { "allowFrom": [6522813629] },
        "nikola": { "allowFrom": [6522813629] },
        "hawthorne": { "allowFrom": [6522813629] },
        "doubtfire": { "allowFrom": [6522813629] },
        "sri_coder": { "allowFrom": [6522813629] },
        "sentry": { "allowFrom": [6522813629] },
        "clawmantha": { "allowFrom": [6522813629] }
      }
    }
  }
}

---

{
  "channel": "telegram",
  "to": "6522813629",
  "accountId": "sentry"
}
RAW_BUFFERClick to expand / collapse

Summary

In a multi-agent OpenClaw deployment with multiple Telegram bot accounts, exec approval delivery ignores approvals.exec.targets[].accountId and fans out the same approval prompt to every Telegram account that can reach the target chat ID.

In our case, a single Sentry exec approval is generated once, but the same approval object is delivered into all Telegram bot threads (Sentry, Clawmantha, Jeffrey, Sri, Mrs_Doubtfire, etc.) instead of only the sentry account specified in config.

This is not an inbound routing issue and not a duplicate of the named-account DM drop fixed in #32426. It appears to be a distinct approval delivery routing bug in the same broader Telegram accountId bug family.

Environment

  • OpenClaw: 2026.4.x stable
  • OS: macOS (arm64)
  • Channel: Telegram, multi-account
  • Gateway mode: local

Relevant config

{
  "approvals": {
    "exec": {
      "enabled": true,
      "mode": "targets",
      "targets": [
        {
          "channel": "telegram",
          "to": "6522813629",
          "accountId": "sentry"
        }
      ]
    }
  },
  "channels": {
    "telegram": {
      "accounts": {
        "default": { "allowFrom": [6522813629] },
        "nikola": { "allowFrom": [6522813629] },
        "hawthorne": { "allowFrom": [6522813629] },
        "doubtfire": { "allowFrom": [6522813629] },
        "sri_coder": { "allowFrom": [6522813629] },
        "sentry": { "allowFrom": [6522813629] },
        "clawmantha": { "allowFrom": [6522813629] }
      }
    }
  }
}

Expected behavior

When approvals.exec.targets specifies:

{
  "channel": "telegram",
  "to": "6522813629",
  "accountId": "sentry"
}

only the Sentry Telegram bot should deliver the exec approval prompt.

Actual behavior

The same exec approval prompt is delivered through all Telegram bot accounts whose allowFrom contains that chat ID.

This creates multiple duplicate approval messages across different agent bot threads for the exact same approval ID.

Evidence

Two example approval ids:

  • 219d461e-891e-4897-ab53-4be350ad0bbb
  • 86120552-282a-471a-8d35-2d38d3f31f82

Local evidence shows:

  1. The approval object originates in Sentry session logs, not independently from the other agents.
  2. The same approval ID is delivered across multiple Telegram bot threads.
  3. Config already specifies a single explicit approval target with accountId: "sentry".

Example Sentry session evidence:

  • approval 219d461e-891e-4897-ab53-4be350ad0bbb appears in the Sentry session transcript with approval-pending
  • the same approval ID then appears in multiple Telegram bot threads for the same human target

This strongly suggests the delivery layer is ignoring accountId when sending exec approval messages and instead iterating all Telegram accounts that can DM the target user.

Why this matters

  • approval spam across every bot thread
  • operator confusion about which bot/thread is authoritative
  • users see the same security prompt 5-7 times for one action
  • makes multi-agent Telegram setups materially worse after hardening / approval enablement

Workarounds attempted

  • Local config already uses a single approval target with explicit accountId
  • Removing allowFrom from the other Telegram accounts would reduce fan-out, but it would also break ordinary DM interaction with those agents
  • No safe local config workaround was found

Related issues

Adjacent Telegram accountId / multi-account routing issues:

  • #5283
  • #9351
  • #17817
  • #21189
  • #36739
  • #26975
  • #17889

This issue appears to be a new manifestation of the same broader accountId routing weakness, specifically in exec approval delivery rather than inbound routing or outbound message-tool routing.

Requested fix

Ensure exec approval delivery honors approvals.exec.targets[].accountId for Telegram and delivers only through the specified Telegram account, not every account whose allowFrom admits the target user.

extent analysis

TL;DR

The most likely fix is to update the approval delivery logic to respect the accountId specified in approvals.exec.targets[] for Telegram, ensuring that exec approvals are only delivered through the intended account.

Guidance

  • Review the approval delivery code to identify where the accountId is being ignored, focusing on the logic that iterates through Telegram accounts for delivery.
  • Verify that the approvals.exec.targets[].accountId value is correctly parsed and applied during the delivery process.
  • Consider adding a filter or conditional statement to ensure that only the specified Telegram account is used for delivery when an accountId is provided.
  • Test the updated logic with multiple Telegram accounts and approval targets to ensure that the fix does not introduce new issues.

Example

// Example approval target with accountId
{
  "channel": "telegram",
  "to": "6522813629",
  "accountId": "sentry"
}

// Pseudo-code for updated delivery logic
if (approvalTarget.accountId) {
  // Filter Telegram accounts to only include the specified accountId
  const targetAccount = telegramAccounts.find(account => account.id === approvalTarget.accountId);
  if (targetAccount) {
    // Deliver approval through the target account
    deliverApprovalThroughAccount(targetAccount, approval);
  }
}

Notes

The provided evidence and config suggest that the issue is specific to the approval delivery layer and its handling of accountId. The fix should focus on updating this logic to respect the specified account.

Recommendation

Apply a workaround by modifying the approval delivery logic to respect the accountId specified in approvals.exec.targets[] for Telegram, as this will directly address the reported issue and prevent approval spam across multiple bot threads.

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

When approvals.exec.targets specifies:

{
  "channel": "telegram",
  "to": "6522813629",
  "accountId": "sentry"
}

only the Sentry Telegram bot should deliver the exec approval prompt.

Still need to ship something?

×6

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

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug]: Telegram exec approvals ignore targets.accountId and fan out across all bot accounts [1 pull requests, 1 participants]