Skip to content

fix: preserve Telegram topic routing for exec completions#64580

Merged
jalehman merged 2 commits into
openclaw:mainfrom
jalehman:clawdbot-a2c-telegram-exec-topic-fix
Apr 11, 2026
Merged

fix: preserve Telegram topic routing for exec completions#64580
jalehman merged 2 commits into
openclaw:mainfrom
jalehman:clawdbot-a2c-telegram-exec-topic-fix

Conversation

@jalehman

Copy link
Copy Markdown
Contributor

What

Preserves the originating delivery context for delayed exec completion events so Telegram forum-topic completions stay pinned to the topic where the work started, even if the session's stored route later drifts to a different topic.

Why

Background exec completions were being queued by session key alone and later re-resolved from mutable session routing state. In Telegram forum topics that could redirect a completion started in one topic into another topic.

Changes

  • Preserve exec completion delivery context on process sessions
  • Attach delivery context to queued exec system events
  • Pass ambient channel delivery context into exec background runs
  • Add Telegram topic regression for topic drift
  • Add notifyOnExit payload coverage for delivery context

Testing

  • pnpm test src/agents/bash-tools.exec-runtime.test.ts src/agents/bash-tools.test.ts src/infra/heartbeat-runner.ghost-reminder.test.ts
  • Expected: targeted agents + infra suites pass, including the new topic 47 vs 2175 regression

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: S maintainer Maintainer-authored PR labels Apr 11, 2026
@greptile-apps

greptile-apps Bot commented Apr 11, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR pins the originating DeliveryContext onto each ProcessSession at spawn time and passes it through to enqueueSystemEvent in maybeNotifyOnExit, replacing the previous behaviour of re-resolving routing from mutable session state at exit time. Three test additions cover the regression (Telegram topic 47 vs 2175), the notifyOnExit payload, and emitExecSystemEvent with a delivery context.

Confidence Score: 5/5

Safe to merge — targeted fix with direct regression test coverage for the topic-drift scenario.

All findings are P2 style suggestions (one redundant normalizeDeliveryContext call). The core fix — pinning DeliveryContext on ProcessSession at spawn time — is correct, and three new tests exercise the exact failure mode from production.

No files require special attention.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/agents/bash-tools.exec-runtime.ts
Line: 577

Comment:
**Double `normalizeDeliveryContext` call**

`opts.notifyDeliveryContext` has already been normalized in `bash-tools.exec.ts` via `normalizeDeliveryContext({...})` before being passed in here (lines 1326–1331 in `bash-tools.exec.ts`). Calling `normalizeDeliveryContext` again on the session is redundant, though harmless. You could store it directly:

```suggestion
    notifyDeliveryContext: opts.notifyDeliveryContext,
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "clawdbot-a2c: pin exec completion delive..." | Re-trigger Greptile

@@ -564,6 +574,7 @@ export async function runExecProcess(opts: {
command: opts.command,
scopeKey: opts.scopeKey,
sessionKey: opts.sessionKey,
notifyDeliveryContext: normalizeDeliveryContext(opts.notifyDeliveryContext),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Double normalizeDeliveryContext call

opts.notifyDeliveryContext has already been normalized in bash-tools.exec.ts via normalizeDeliveryContext({...}) before being passed in here (lines 1326–1331 in bash-tools.exec.ts). Calling normalizeDeliveryContext again on the session is redundant, though harmless. You could store it directly:

Suggested change
notifyDeliveryContext: normalizeDeliveryContext(opts.notifyDeliveryContext),
notifyDeliveryContext: opts.notifyDeliveryContext,
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/bash-tools.exec-runtime.ts
Line: 577

Comment:
**Double `normalizeDeliveryContext` call**

`opts.notifyDeliveryContext` has already been normalized in `bash-tools.exec.ts` via `normalizeDeliveryContext({...})` before being passed in here (lines 1326–1331 in `bash-tools.exec.ts`). Calling `normalizeDeliveryContext` again on the session is redundant, though harmless. You could store it directly:

```suggestion
    notifyDeliveryContext: opts.notifyDeliveryContext,
```

How can I resolve this? If you propose a fix, please make it concise.

@jalehman jalehman self-assigned this Apr 11, 2026
@aisle-research-bot

aisle-research-bot Bot commented Apr 11, 2026

Copy link
Copy Markdown

🔒 Aisle Security Analysis

We found 1 potential security issue(s) in this PR:

# Severity Title
1 🟡 Medium Ambiguous/unvalidated DeliveryContext fields allow delimiter/control-character injection into deliveryContextKey
1. 🟡 Ambiguous/unvalidated DeliveryContext fields allow delimiter/control-character injection into deliveryContextKey
Property Value
Severity Medium
CWE CWE-20
Location src/utils/delivery-context.shared.ts:7-40

Description

normalizeDeliveryContext() only trims string fields and allows arbitrary characters in to and threadId (including control characters and the | delimiter). deliveryContextKey() then concatenates these unescaped fields with |, creating an ambiguous composite key.

This becomes security-relevant because delivery-context keys are used to group/compare routing contexts (e.g., announce queues, session delivery comparisons). If an attacker can influence DeliveryContext.to/threadId (directly or indirectly via message metadata), they may be able to:

  • Cause key collisions / parsing ambiguities by injecting | into to or threadId, potentially mixing events/routes across distinct destinations.
  • Inject control characters (e.g., CR/LF) into values that may later be logged or embedded into human-readable summaries, increasing risk of log injection / confusing audit trails.

Vulnerable code:

const to = normalizeOptionalString(context.to);
...
return `${normalized.channel}|${normalized.to}|${normalized.accountId ?? ""}|${threadId}`;

Although this diff primarily adds new call sites that pass DeliveryContext through (e.g., exec notifications), the underlying normalization/keying accepts attacker-controlled strings without enforcing a safe character set or escaping, which can lead to malformed routing keys and mis-association of deliveries/events.

Recommendation

Harden DeliveryContext normalization and key construction:

  1. Reject or escape delimiters and control characters in channel, to, and threadId.
  2. Prefer structured keys (e.g., JSON serialization with stable encoding) or an escaping scheme instead of raw concatenation.

Example (reject unsafe characters and ensure threadId is consistently stringified):

const UNSAFE_RE = /[\r\n\u0000-\u001f\u007f|]/;

function normalizeSafeField(v: unknown): string | undefined {
  const s = normalizeOptionalString(v);
  if (!s) return undefined;
  if (UNSAFE_RE.test(s)) return undefined; // or escape
  return s;
}

export function normalizeDeliveryContext(context?: DeliveryContext): DeliveryContext | undefined {
  if (!context) return undefined;
  const channel = normalizeSafeField(context.channel);
  const to = normalizeSafeField(context.to);
  const accountId = normalizeAccountId(context.accountId);
  const threadIdRaw = (typeof context.threadId === "number" && Number.isFinite(context.threadId))
    ? String(Math.trunc(context.threadId))
    : normalizeSafeField(context.threadId);

  if (!channel && !to && !accountId && !threadIdRaw) return undefined;
  return { channel, to, accountId, ...(threadIdRaw ? { threadId: threadIdRaw } : {}) };
}

export function deliveryContextKey(context?: DeliveryContext): string | undefined {
  const n = normalizeDeliveryContext(context);
  if (!n?.channel || !n?.to) return undefined;
  return JSON.stringify([n.channel, n.to, n.accountId ?? "", n.threadId ?? ""]);
}

Also ensure downstream routing code uses the normalized/validated form exclusively.


Analyzed PR: #64580 at commit f13fb58

Last updated on: 2026-04-11T22:35:42Z

@jalehman
jalehman force-pushed the clawdbot-a2c-telegram-exec-topic-fix branch from b896d96 to d2a4b38 Compare April 11, 2026 16:09
Regeneration-Prompt: |
  Fix a Telegram forum topic misroute where delayed exec completion or similar async completion text could be delivered into the wrong topic after the session's stored route drifted. Keep the patch surgical. Preserve immutable origin deliveryContext when background exec completion events are queued, thread that context from the exec tool's ambient channel/session defaults into the process session, and ensure the queued system event carries it instead of relying on later heartbeat fallback to mutable session lastTo/lastThreadId data. Add one focused unit assertion that notifyOnExit events keep the original Telegram topic delivery context and one heartbeat regression that proves work started in topic 47 still delivers back to topic 47 even if the session store later points at topic 2175.
Regeneration-Prompt: |
  Prepare PR openclaw#64580 after review-pr with no blocking findings. The only required prep change was the workflow-mandated changelog entry under CHANGELOG.md -> Unreleased -> Fixes. Preserve the review conclusion that the code change is already acceptable, do not widen scope beyond the changelog, and include the PR number plus thanks attribution in the changelog line for the Telegram exec forum-topic completion routing fix.
@jalehman
jalehman force-pushed the clawdbot-a2c-telegram-exec-topic-fix branch from d2a4b38 to f13fb58 Compare April 11, 2026 22:32
@jalehman
jalehman merged commit 29142a9 into openclaw:main Apr 11, 2026
39 of 41 checks passed
trudbot pushed a commit to trudbot/openclaw that referenced this pull request Apr 12, 2026
…4580)

* clawdbot-a2c: pin exec completion delivery context

Regeneration-Prompt: |
  Fix a Telegram forum topic misroute where delayed exec completion or similar async completion text could be delivered into the wrong topic after the session's stored route drifted. Keep the patch surgical. Preserve immutable origin deliveryContext when background exec completion events are queued, thread that context from the exec tool's ambient channel/session defaults into the process session, and ensure the queued system event carries it instead of relying on later heartbeat fallback to mutable session lastTo/lastThreadId data. Add one focused unit assertion that notifyOnExit events keep the original Telegram topic delivery context and one heartbeat regression that proves work started in topic 47 still delivers back to topic 47 even if the session store later points at topic 2175.

* fix: note Telegram exec topic routing

Regeneration-Prompt: |
  Prepare PR openclaw#64580 after review-pr with no blocking findings. The only required prep change was the workflow-mandated changelog entry under CHANGELOG.md -> Unreleased -> Fixes. Preserve the review conclusion that the code change is already acceptable, do not widen scope beyond the changelog, and include the PR number plus thanks attribution in the changelog line for the Telegram exec forum-topic completion routing fix.
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
…4580)

* clawdbot-a2c: pin exec completion delivery context

Regeneration-Prompt: |
  Fix a Telegram forum topic misroute where delayed exec completion or similar async completion text could be delivered into the wrong topic after the session's stored route drifted. Keep the patch surgical. Preserve immutable origin deliveryContext when background exec completion events are queued, thread that context from the exec tool's ambient channel/session defaults into the process session, and ensure the queued system event carries it instead of relying on later heartbeat fallback to mutable session lastTo/lastThreadId data. Add one focused unit assertion that notifyOnExit events keep the original Telegram topic delivery context and one heartbeat regression that proves work started in topic 47 still delivers back to topic 47 even if the session store later points at topic 2175.

* fix: note Telegram exec topic routing

Regeneration-Prompt: |
  Prepare PR openclaw#64580 after review-pr with no blocking findings. The only required prep change was the workflow-mandated changelog entry under CHANGELOG.md -> Unreleased -> Fixes. Preserve the review conclusion that the code change is already acceptable, do not widen scope beyond the changelog, and include the PR number plus thanks attribution in the changelog line for the Telegram exec forum-topic completion routing fix.
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
…4580)

* clawdbot-a2c: pin exec completion delivery context

Regeneration-Prompt: |
  Fix a Telegram forum topic misroute where delayed exec completion or similar async completion text could be delivered into the wrong topic after the session's stored route drifted. Keep the patch surgical. Preserve immutable origin deliveryContext when background exec completion events are queued, thread that context from the exec tool's ambient channel/session defaults into the process session, and ensure the queued system event carries it instead of relying on later heartbeat fallback to mutable session lastTo/lastThreadId data. Add one focused unit assertion that notifyOnExit events keep the original Telegram topic delivery context and one heartbeat regression that proves work started in topic 47 still delivers back to topic 47 even if the session store later points at topic 2175.

* fix: note Telegram exec topic routing

Regeneration-Prompt: |
  Prepare PR openclaw#64580 after review-pr with no blocking findings. The only required prep change was the workflow-mandated changelog entry under CHANGELOG.md -> Unreleased -> Fixes. Preserve the review conclusion that the code change is already acceptable, do not widen scope beyond the changelog, and include the PR number plus thanks attribution in the changelog line for the Telegram exec forum-topic completion routing fix.
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
…4580)

* clawdbot-a2c: pin exec completion delivery context

Regeneration-Prompt: |
  Fix a Telegram forum topic misroute where delayed exec completion or similar async completion text could be delivered into the wrong topic after the session's stored route drifted. Keep the patch surgical. Preserve immutable origin deliveryContext when background exec completion events are queued, thread that context from the exec tool's ambient channel/session defaults into the process session, and ensure the queued system event carries it instead of relying on later heartbeat fallback to mutable session lastTo/lastThreadId data. Add one focused unit assertion that notifyOnExit events keep the original Telegram topic delivery context and one heartbeat regression that proves work started in topic 47 still delivers back to topic 47 even if the session store later points at topic 2175.

* fix: note Telegram exec topic routing

Regeneration-Prompt: |
  Prepare PR openclaw#64580 after review-pr with no blocking findings. The only required prep change was the workflow-mandated changelog entry under CHANGELOG.md -> Unreleased -> Fixes. Preserve the review conclusion that the code change is already acceptable, do not widen scope beyond the changelog, and include the PR number plus thanks attribution in the changelog line for the Telegram exec forum-topic completion routing fix.
globalcaos pushed a commit to globalcaos/tinkerclaw that referenced this pull request May 13, 2026
…4580)

* clawdbot-a2c: pin exec completion delivery context

Regeneration-Prompt: |
  Fix a Telegram forum topic misroute where delayed exec completion or similar async completion text could be delivered into the wrong topic after the session's stored route drifted. Keep the patch surgical. Preserve immutable origin deliveryContext when background exec completion events are queued, thread that context from the exec tool's ambient channel/session defaults into the process session, and ensure the queued system event carries it instead of relying on later heartbeat fallback to mutable session lastTo/lastThreadId data. Add one focused unit assertion that notifyOnExit events keep the original Telegram topic delivery context and one heartbeat regression that proves work started in topic 47 still delivers back to topic 47 even if the session store later points at topic 2175.

* fix: note Telegram exec topic routing

Regeneration-Prompt: |
  Prepare PR openclaw#64580 after review-pr with no blocking findings. The only required prep change was the workflow-mandated changelog entry under CHANGELOG.md -> Unreleased -> Fixes. Preserve the review conclusion that the code change is already acceptable, do not widen scope beyond the changelog, and include the PR number plus thanks attribution in the changelog line for the Telegram exec forum-topic completion routing fix.
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
…4580)

* clawdbot-a2c: pin exec completion delivery context

Regeneration-Prompt: |
  Fix a Telegram forum topic misroute where delayed exec completion or similar async completion text could be delivered into the wrong topic after the session's stored route drifted. Keep the patch surgical. Preserve immutable origin deliveryContext when background exec completion events are queued, thread that context from the exec tool's ambient channel/session defaults into the process session, and ensure the queued system event carries it instead of relying on later heartbeat fallback to mutable session lastTo/lastThreadId data. Add one focused unit assertion that notifyOnExit events keep the original Telegram topic delivery context and one heartbeat regression that proves work started in topic 47 still delivers back to topic 47 even if the session store later points at topic 2175.

* fix: note Telegram exec topic routing

Regeneration-Prompt: |
  Prepare PR openclaw#64580 after review-pr with no blocking findings. The only required prep change was the workflow-mandated changelog entry under CHANGELOG.md -> Unreleased -> Fixes. Preserve the review conclusion that the code change is already acceptable, do not widen scope beyond the changelog, and include the PR number plus thanks attribution in the changelog line for the Telegram exec forum-topic completion routing fix.
jameslcowan pushed a commit to jameslcowan/openclaw that referenced this pull request Jun 2, 2026
…4580)

* clawdbot-a2c: pin exec completion delivery context

Regeneration-Prompt: |
  Fix a Telegram forum topic misroute where delayed exec completion or similar async completion text could be delivered into the wrong topic after the session's stored route drifted. Keep the patch surgical. Preserve immutable origin deliveryContext when background exec completion events are queued, thread that context from the exec tool's ambient channel/session defaults into the process session, and ensure the queued system event carries it instead of relying on later heartbeat fallback to mutable session lastTo/lastThreadId data. Add one focused unit assertion that notifyOnExit events keep the original Telegram topic delivery context and one heartbeat regression that proves work started in topic 47 still delivers back to topic 47 even if the session store later points at topic 2175.

* fix: note Telegram exec topic routing

Regeneration-Prompt: |
  Prepare PR openclaw#64580 after review-pr with no blocking findings. The only required prep change was the workflow-mandated changelog entry under CHANGELOG.md -> Unreleased -> Fixes. Preserve the review conclusion that the code change is already acceptable, do not widen scope beyond the changelog, and include the PR number plus thanks attribution in the changelog line for the Telegram exec forum-topic completion routing fix.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling maintainer Maintainer-authored PR size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant