VYPR
Medium severity5.3NVD Advisory· Published Apr 10, 2026· Updated Apr 13, 2026

CVE-2026-35661

CVE-2026-35661

Description

OpenClaw before 2026.3.25 contains an authorization bypass vulnerability in Telegram callback query handling that allows attackers to mutate session state without satisfying normal DM pairing requirements. Remote attackers can exploit weaker callback-only authorization in direct messages to bypass DM pairing and modify session state.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
openclawnpm
< 2026.3.282026.3.28

Affected products

1
  • cpe:2.3:a:openclaw:openclaw:*:*:*:*:*:node.js:*:*
    Range: <2026.3.25

Patches

1
269282ac69ab

Telegram: enforce DM auth for callbacks (#55112)

https://github.com/openclaw/openclawJacob TomlinsonMar 26, 2026via ghsa
2 files changed · +68 1
  • extensions/telegram/src/bot-handlers.runtime.ts+2 1 modified
    @@ -1242,8 +1242,9 @@ export const registerTelegramHandlers = ({
           }
           const senderId = callback.from?.id ? String(callback.from.id) : "";
           const senderUsername = callback.from?.username ?? "";
    +      // DM callbacks must enforce the same sender authorization gate as normal DM commands.
           const authorizationMode: TelegramEventAuthorizationMode =
    -        !execApprovalButtonsEnabled && inlineButtonsScope === "allowlist"
    +        !isGroup || (!execApprovalButtonsEnabled && inlineButtonsScope === "allowlist")
               ? "callback-allowlist"
               : "callback-scope";
           const senderAuthorization = authorizeTelegramEventSender({
    
  • extensions/telegram/src/bot.test.ts+66 0 modified
    @@ -253,6 +253,72 @@ describe("createTelegramBot", () => {
         expect(answerCallbackQuerySpy).toHaveBeenCalledWith("cbq-2");
       });
     
    +  it("blocks DM model-selection callbacks for unpaired users when inline buttons are DM-scoped", async () => {
    +    onSpy.mockClear();
    +    replySpy.mockClear();
    +    editMessageTextSpy.mockClear();
    +
    +    const storePath = `/tmp/openclaw-telegram-callback-authz-${process.pid}-${Date.now()}.json`;
    +
    +    await rm(storePath, { force: true });
    +    try {
    +      const config = {
    +        agents: {
    +          defaults: {
    +            model: "anthropic/claude-opus-4-6",
    +            models: {
    +              "anthropic/claude-opus-4-6": {},
    +              "openai/gpt-5.4": {},
    +            },
    +          },
    +        },
    +        channels: {
    +          telegram: {
    +            dmPolicy: "pairing",
    +            capabilities: { inlineButtons: "dm" },
    +          },
    +        },
    +        session: {
    +          store: storePath,
    +        },
    +      } satisfies NonNullable<Parameters<typeof createTelegramBot>[0]["config"]>;
    +
    +      loadConfig.mockReturnValue(config);
    +      readChannelAllowFromStore.mockResolvedValueOnce([]);
    +
    +      createTelegramBot({
    +        token: "tok",
    +        config,
    +      });
    +      const callbackHandler = onSpy.mock.calls.find(
    +        (call) => call[0] === "callback_query",
    +      )?.[1] as (ctx: Record<string, unknown>) => Promise<void>;
    +      expect(callbackHandler).toBeDefined();
    +
    +      await callbackHandler({
    +        callbackQuery: {
    +          id: "cbq-model-authz-bypass-1",
    +          data: "mdl_sel_openai/gpt-5.4",
    +          from: { id: 999, first_name: "Mallory", username: "mallory" },
    +          message: {
    +            chat: { id: 1234, type: "private" },
    +            date: 1736380800,
    +            message_id: 19,
    +          },
    +        },
    +        me: { username: "openclaw_bot" },
    +        getFile: async () => ({ download: async () => new Uint8Array() }),
    +      });
    +
    +      expect(replySpy).not.toHaveBeenCalled();
    +      expect(editMessageTextSpy).not.toHaveBeenCalled();
    +      expect(loadSessionStore(storePath, { skipCache: true })).toEqual({});
    +      expect(answerCallbackQuerySpy).toHaveBeenCalledWith("cbq-model-authz-bypass-1");
    +    } finally {
    +      await rm(storePath, { force: true });
    +    }
    +  });
    +
       it("allows callback_query in groups when group policy authorizes the sender", async () => {
         onSpy.mockClear();
         editMessageTextSpy.mockClear();
    

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

5

News mentions

0

No linked articles in our index yet.