High severity8.8NVD Advisory· Published May 6, 2026· Updated May 7, 2026
CVE-2026-44110
CVE-2026-44110
Description
OpenClaw before 2026.4.15 contains an authorization bypass vulnerability in Matrix room control-command authorization that trusts DM pairing-store entries. Attackers with DM-paired sender IDs can execute room control commands without being in configured allowlists by posting in bot rooms, potentially enabling privileged OpenClaw behavior.
Affected products
2Patches
22bfd808a8311fix(matrix): skip pairing-store reads for room auth (#67325)
3 files changed · +5 −2
CHANGELOG.md+1 −0 modified@@ -16,6 +16,7 @@ Docs: https://docs.openclaw.ai - Plugins/bundled channels: partition bundled channel lazy caches by active bundled root so `OPENCLAW_BUNDLED_PLUGINS_DIR` flips stop reusing stale plugin, setup, secrets, and runtime state. (#67200) Thanks @gumadeiras. - Packaging/plugins: prune common test/spec cargo from bundled plugin runtime dependencies and fail npm release validation if packaged test cargo reappears, keeping published tarballs leaner without plugin-specific special cases. (#67275) thanks @gumadeiras. - Agents/context + Memory: trim default startup/skills prompt budgets, cap `memory_get` excerpts by default with explicit continuation metadata, and keep QMD reads aligned with the same bounded excerpt contract so long sessions pull less context by default without losing deterministic follow-up reads. +- Matrix/commands: skip DM pairing-store reads on room traffic now that room control-command authorization ignores pairing-store entries, keeping the room path narrower without changing room auth behavior. (#67325) Thanks @gumadeiras. ## 2026.4.15-beta.1
extensions/matrix/src/matrix/monitor/handler.test.ts+3 −1 modified@@ -446,10 +446,11 @@ describe("matrix monitor handler pairing account scope", () => { }); it("blocks room control commands from DM-only paired senders", async () => { + const readAllowFromStore = vi.fn(async () => ["@user:example.org"]); const { handler, finalizeInboundContext, recordInboundSession } = createMatrixHandlerTestHarness({ isDirectMessage: false, - readAllowFromStore: vi.fn(async () => ["@user:example.org"]), + readAllowFromStore, roomsConfig: { "!room:example.org": { requireMention: false }, }, @@ -473,6 +474,7 @@ describe("matrix monitor handler pairing account scope", () => { expect(recordInboundSession).not.toHaveBeenCalled(); expect(finalizeInboundContext).not.toHaveBeenCalled(); + expect(readAllowFromStore).not.toHaveBeenCalled(); }); it("processes room messages mentioned via displayName in formatted_body", async () => {
extensions/matrix/src/matrix/monitor/handler.ts+1 −1 modified@@ -586,7 +586,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam senderNamePromise ??= getMemberDisplayName(roomId, senderId).catch(() => senderId); return await senderNamePromise; }; - const storeAllowFrom = await readStoreAllowFrom(); + const storeAllowFrom = isDirectMessage ? await readStoreAllowFrom() : []; const roomUsers = roomConfig?.users ?? []; const accessState = resolveMatrixMonitorAccessState({ allowFrom,
f8705f512b09fix(matrix): block DM pairing-store entries from authorizing room control commands [AI-assisted] (#67294)
4 files changed · +71 −7
CHANGELOG.md+1 −0 modified@@ -8,6 +8,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- fix(matrix): block DM pairing-store entries from authorizing room control commands [AI-assisted]. (#67294) Thanks @pgondhi987. - Docker/build: verify `@matrix-org/matrix-sdk-crypto-nodejs` native bindings with `find` under `node_modules` instead of a hardcoded `.pnpm/...` path so pnpm v10+ virtual-store layouts no longer fail the image build. (#67143) thanks @ly85206559. - Matrix/E2EE: keep startup bootstrap conservative for passwordless token-auth bots, still attempt the guarded repair pass without requiring `channels.matrix.password`, and document the remaining password-UIA limitation. (#66228) Thanks @SARAMALI15792. - Cron/announce delivery: suppress mixed-content isolated cron announce replies that end with `NO_REPLY` so trailing silent sentinels no longer leak summary text to the target channel. (#65004) thanks @neo1027144-creator.
extensions/matrix/src/matrix/monitor/access-state.test.ts+19 −0 modified@@ -28,6 +28,25 @@ describe("resolveMatrixMonitorAccessState", () => { ]); }); + it("does not let DM pairing-store entries authorize room control commands", () => { + const state = resolveMatrixMonitorAccessState({ + allowFrom: [], + storeAllowFrom: ["@attacker:example.org"], + groupAllowFrom: [], + roomUsers: [], + senderId: "@attacker:example.org", + isRoom: true, + }); + + expect(state.effectiveAllowFrom).toEqual(["@attacker:example.org"]); + expect(state.directAllowMatch.allowed).toBe(true); + expect(state.commandAuthorizers).toEqual([ + { configured: false, allowed: false }, + { configured: false, allowed: false }, + { configured: false, allowed: false }, + ]); + }); + it("keeps room-user matching disabled for dm traffic", () => { const state = resolveMatrixMonitorAccessState({ allowFrom: [],
extensions/matrix/src/matrix/monitor/access-state.ts+21 −7 modified@@ -1,19 +1,24 @@ import { normalizeMatrixAllowList, resolveMatrixAllowListMatch } from "./allowlist.js"; -import type { MatrixAllowListMatch } from "./allowlist.js"; type MatrixCommandAuthorizer = { configured: boolean; allowed: boolean; }; +type MatrixMonitorAllowListMatch = { + allowed: boolean; + matchKey?: string; + matchSource?: "wildcard" | "id" | "prefixed-id" | "prefixed-user"; +}; + export type MatrixMonitorAccessState = { effectiveAllowFrom: string[]; effectiveGroupAllowFrom: string[]; effectiveRoomUsers: string[]; groupAllowConfigured: boolean; - directAllowMatch: MatrixAllowListMatch; - roomUserMatch: MatrixAllowListMatch | null; - groupAllowMatch: MatrixAllowListMatch | null; + directAllowMatch: MatrixMonitorAllowListMatch; + roomUserMatch: MatrixMonitorAllowListMatch | null; + groupAllowMatch: MatrixMonitorAllowListMatch | null; commandAuthorizers: [MatrixCommandAuthorizer, MatrixCommandAuthorizer, MatrixCommandAuthorizer]; }; @@ -25,12 +30,14 @@ export function resolveMatrixMonitorAccessState(params: { senderId: string; isRoom: boolean; }): MatrixMonitorAccessState { + const configuredAllowFrom = normalizeMatrixAllowList(params.allowFrom); const effectiveAllowFrom = normalizeMatrixAllowList([ - ...params.allowFrom, + ...configuredAllowFrom, ...params.storeAllowFrom, ]); const effectiveGroupAllowFrom = normalizeMatrixAllowList(params.groupAllowFrom); const effectiveRoomUsers = normalizeMatrixAllowList(params.roomUsers); + const commandAllowFrom = params.isRoom ? configuredAllowFrom : effectiveAllowFrom; const directAllowMatch = resolveMatrixAllowListMatch({ allowList: effectiveAllowFrom, @@ -50,6 +57,13 @@ export function resolveMatrixMonitorAccessState(params: { userId: params.senderId, }) : null; + const commandAllowMatch = + commandAllowFrom.length > 0 + ? resolveMatrixAllowListMatch({ + allowList: commandAllowFrom, + userId: params.senderId, + }) + : null; return { effectiveAllowFrom, @@ -61,8 +75,8 @@ export function resolveMatrixMonitorAccessState(params: { groupAllowMatch, commandAuthorizers: [ { - configured: effectiveAllowFrom.length > 0, - allowed: directAllowMatch.allowed, + configured: commandAllowFrom.length > 0, + allowed: commandAllowMatch?.allowed ?? false, }, { configured: effectiveRoomUsers.length > 0,
extensions/matrix/src/matrix/monitor/handler.test.ts+30 −0 modified@@ -445,6 +445,36 @@ describe("matrix monitor handler pairing account scope", () => { expect(recordInboundSession).not.toHaveBeenCalled(); }); + it("blocks room control commands from DM-only paired senders", async () => { + const { handler, finalizeInboundContext, recordInboundSession } = + createMatrixHandlerTestHarness({ + isDirectMessage: false, + readAllowFromStore: vi.fn(async () => ["@user:example.org"]), + roomsConfig: { + "!room:example.org": { requireMention: false }, + }, + shouldHandleTextCommands: () => true, + hasControlCommand: () => true, + cfg: { + commands: { + useAccessGroups: true, + }, + }, + getMemberDisplayName: async () => "sender", + }); + + await handler( + "!room:example.org", + createMatrixTextMessageEvent({ + eventId: "$dm-only-room-command", + body: "/config", + }), + ); + + expect(recordInboundSession).not.toHaveBeenCalled(); + expect(finalizeInboundContext).not.toHaveBeenCalled(); + }); + it("processes room messages mentioned via displayName in formatted_body", async () => { const recordInboundSession = vi.fn(async () => {}); const { handler } = createMatrixHandlerTestHarness({
Vulnerability mechanics
AI mechanics synthesis has not run for this CVE yet.
References
8- github.com/openclaw/openclaw/commit/2bfd808a83116bd888e3e2633a61473fa2ed81b6nvdPatch
- github.com/openclaw/openclaw/commit/f8705f512b09043df02b5da372c33374734bd921nvdPatch
- github.com/advisories/GHSA-2gvc-4f3c-2855ghsaADVISORY
- github.com/openclaw/openclaw/security/advisories/GHSA-2gvc-4f3c-2855nvdMitigationVendor Advisory
- www.vulncheck.com/advisories/openclaw-authorization-bypass-in-matrix-room-control-commands-via-dm-pairing-storenvdThird Party Advisory
- github.com/openclaw/openclaw/pull/67294ghsa
- github.com/openclaw/openclaw/pull/67325ghsa
- nvd.nist.gov/vuln/detail/CVE-2026-44110ghsa
News mentions
9- 30 ClawHub skills secretly turn AI agents into a crypto swarmThe Register Security · Apr 29, 2026
- 30 ClawHub skills secretly turn AI agents into a crypto swarmThe Register Security · Apr 29, 2026
- 27th April – Threat Intelligence ReportCheck Point Research · Apr 27, 2026
- Agents that remember: introducing Agent MemoryCloudflare Blog · Apr 17, 2026
- The Increasing Role of AI in Vulnerability ResearchWordfence Blog · Apr 10, 2026
- 16th March – Threat Intelligence ReportCheck Point Research · Mar 16, 2026
- How AI Assistants are Moving the Security GoalpostsKrebs on Security · Mar 8, 2026
- Risky Business #827 -- Iranian cyber threat actors are down but not outRisky Business · Mar 4, 2026
- Risky Business #826 -- A week of AI mishaps and skulduggeryRisky Business · Feb 25, 2026