OpenClaw: Telegram bot token exposure via logs
Description
OpenClaw is a personal AI assistant. Telegram bot tokens can appear in error messages and stack traces (for example, when request URLs include https://api.telegram.org/bot<token>/...). Prior to version 2026.2.15, OpenClaw logged these strings without redaction, which could leak the bot token into logs, crash reports, CI output, or support bundles. Disclosure of a Telegram bot token allows an attacker to impersonate the bot and take over Bot API access. Users should upgrade to version 2026.2.15 to obtain a fix and rotate the Telegram bot token if it may have been exposed.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
openclawnpm | < 2026.2.15 | 2026.2.15 |
Affected products
1Patches
1cf69907015b6fix(security): redact Telegram bot tokens in errors
4 files changed · +32 −14
CHANGELOG.md+1 −0 modified@@ -19,6 +19,7 @@ Docs: https://docs.openclaw.ai - Control UI: prevent stored XSS via assistant name/avatar by removing inline script injection, serving bootstrap config as JSON, and enforcing `script-src 'self'`. Thanks @Adam55A-code. - Discord: preserve channel session continuity when runtime payloads omit `message.channelId` by falling back to event/raw `channel_id` values for routing/session keys, so same-channel messages keep history across turns/restarts. Also align diagnostics so active Discord runs no longer appear as `sessionKey=unknown`. (#17622) Thanks @shakkernerd. - Web UI/Agents: hide `BOOTSTRAP.md` in the Agents Files list after onboarding is completed, avoiding confusing missing-file warnings for completed workspaces. (#17491) Thanks @gumadeiras. +- Security/Logging: redact Telegram bot tokens from error messages and uncaught stack traces to prevent accidental secret leakage into logs. Thanks @aether-ai-agent. - Telegram: omit `message_thread_id` for DM sends/draft previews and keep forum-topic handling (`id=1` general omitted, non-general kept), preventing DM failures with `400 Bad Request: message thread not found`. (#10942) Thanks @garnetlyx. - Dev tooling: harden git `pre-commit` hook against option injection from malicious filenames (for example `--force`), preventing accidental staging of ignored files. Thanks @mrthankyou. - Subagents/Models: preserve `agents.defaults.model.fallbacks` when subagent sessions carry a model override, so subagent runs fail over to configured fallback models instead of retrying only the overridden primary model.
src/infra/errors.ts+19 −14 modified@@ -1,3 +1,5 @@ +import { redactSensitiveText } from "../logging/redact.js"; + export function extractErrorCode(err: unknown): string | undefined { if (!err || typeof err !== "object") { return undefined; @@ -27,28 +29,31 @@ export function hasErrnoCode(err: unknown, code: string): boolean { } export function formatErrorMessage(err: unknown): string { + let formatted: string; if (err instanceof Error) { - return err.message || err.name || "Error"; - } - if (typeof err === "string") { - return err; - } - if (typeof err === "number" || typeof err === "boolean" || typeof err === "bigint") { - return String(err); - } - try { - return JSON.stringify(err); - } catch { - return Object.prototype.toString.call(err); - } + formatted = err.message || err.name || "Error"; + } else if (typeof err === "string") { + formatted = err; + } else if (typeof err === "number" || typeof err === "boolean" || typeof err === "bigint") { + formatted = String(err); + } else { + try { + formatted = JSON.stringify(err); + } catch { + formatted = Object.prototype.toString.call(err); + } + } + // Security: best-effort token redaction before returning/logging. + return redactSensitiveText(formatted); } export function formatUncaughtError(err: unknown): string { if (extractErrorCode(err) === "INVALID_CONFIG") { return formatErrorMessage(err); } if (err instanceof Error) { - return err.stack ?? err.message ?? err.name; + const stack = err.stack ?? err.message ?? err.name; + return redactSensitiveText(stack); } return formatErrorMessage(err); }
src/logging/redact.test.ts+10 −0 modified@@ -49,6 +49,16 @@ describe("redactSensitiveText", () => { expect(output).toBe("123456…cdef"); }); + it("masks Telegram Bot API URL tokens", () => { + const input = + "GET https://api.telegram.org/bot123456:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef/getMe HTTP/1.1"; + const output = redactSensitiveText(input, { + mode: "tools", + patterns: defaults, + }); + expect(output).toBe("GET https://api.telegram.org/bot123456…cdef/getMe HTTP/1.1"); + }); + it("redacts short tokens fully", () => { const input = "TOKEN=shortvalue"; const output = redactSensitiveText(input, {
src/logging/redact.ts+2 −0 modified@@ -32,6 +32,8 @@ const DEFAULT_REDACT_PATTERNS: string[] = [ String.raw`\b(AIza[0-9A-Za-z\-_]{20,})\b`, String.raw`\b(pplx-[A-Za-z0-9_-]{10,})\b`, String.raw`\b(npm_[A-Za-z0-9]{10,})\b`, + // Telegram Bot API URLs embed the token as `/bot<token>/...` (no word-boundary before digits). + String.raw`\bbot(\d{6,}:[A-Za-z0-9_-]{20,})\b`, String.raw`\b(\d{6,}:[A-Za-z0-9_-]{20,})\b`, ];
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4- github.com/advisories/GHSA-chf7-jq6g-qrwvghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-27003ghsaADVISORY
- github.com/openclaw/openclaw/commit/cf69907015b659e5025efb735ee31bd05c4ee3d5ghsax_refsource_MISCWEB
- github.com/openclaw/openclaw/security/advisories/GHSA-chf7-jq6g-qrwvghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.