Medium severity4.3NVD Advisory· Published Mar 31, 2026· Updated Apr 1, 2026
CVE-2026-33578
CVE-2026-33578
Description
OpenClaw before 2026.3.28 contains a sender policy bypass vulnerability in the Google Chat and Zalouser extensions where route-level group allowlist policies silently downgrade to open policy. Attackers can exploit this policy resolution flaw to bypass sender restrictions and interact with bots despite configured allowlist restrictions.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
openclawnpm | < 2026.3.28 | 2026.3.28 |
Affected products
1Patches
1e64a881ae0fbChannels: preserve routed group policy (#56011)
4 files changed · +57 −12
extensions/googlechat/src/monitor-access.test.ts+39 −0 modified@@ -213,6 +213,45 @@ describe("googlechat inbound access policy", () => { }); }); + it("preserves allowlist group policy when a routed space has no sender allowlist", async () => { + primeCommonDefaults(); + allowInboundGroupTraffic({ + effectiveGroupAllowFrom: [], + effectiveWasMentioned: false, + }); + resolveSenderScopedGroupPolicy.mockReturnValue("open"); + resolveSenderScopedGroupPolicy.mockClear(); + resolveDmGroupAccessWithLists.mockClear(); + + await expect( + applyInboundAccessPolicy({ + account: { + accountId: "default", + config: { + groups: { + "spaces/AAA": { + allow: true, + }, + }, + }, + } as never, + }), + ).resolves.toEqual({ + ok: true, + commandAuthorized: undefined, + effectiveWasMentioned: false, + groupSystemPrompt: undefined, + }); + + expect(resolveSenderScopedGroupPolicy).not.toHaveBeenCalled(); + expect(resolveDmGroupAccessWithLists).toHaveBeenCalledWith( + expect.objectContaining({ + groupPolicy: "allowlist", + groupAllowFrom: [], + }), + ); + }); + it("drops unauthorized group control commands", async () => { primeCommonDefaults(); allowInboundGroupTraffic({
extensions/googlechat/src/monitor-access.ts+7 −4 modified@@ -271,10 +271,13 @@ export async function applyGoogleChatInboundAccessPolicy(params: { const dmPolicy = account.config.dm?.policy ?? "pairing"; const configAllowFrom = (account.config.dm?.allowFrom ?? []).map((v) => String(v)); const normalizedGroupUsers = groupUsers.map((v) => String(v)); - const senderGroupPolicy = resolveSenderScopedGroupPolicy({ - groupPolicy, - groupAllowFrom: normalizedGroupUsers, - }); + const senderGroupPolicy = + groupConfigResolved.allowlistConfigured && normalizedGroupUsers.length === 0 + ? groupPolicy + : resolveSenderScopedGroupPolicy({ + groupPolicy, + groupAllowFrom: normalizedGroupUsers, + }); const shouldComputeAuth = core.channel.commands.shouldComputeCommandAuthorized(rawBody, config); const storeAllowFrom = !isGroup && dmPolicy !== "allowlist" && (dmPolicy !== "open" || shouldComputeAuth)
extensions/zalouser/src/monitor.group-gating.test.ts+2 −3 modified@@ -507,10 +507,9 @@ describe("zalouser monitor group mention gating", () => { }); }); - it("allows allowlisted group replies without inheriting the DM allowlist", async () => { + it("blocks routed allowlist groups without an explicit group sender allowlist", async () => { const { dispatchReplyWithBufferedBlockDispatcher } = installRuntime({ commandAuthorized: false, - replyPayload: { text: "ok" }, }); await __testing.processMessage({ message: createGroupMessage({ @@ -534,7 +533,7 @@ describe("zalouser monitor group mention gating", () => { runtime: createRuntimeEnv(), }); - expect(dispatchReplyWithBufferedBlockDispatcher).toHaveBeenCalledTimes(1); + expect(dispatchReplyWithBufferedBlockDispatcher).not.toHaveBeenCalled(); }); it("blocks group messages when sender is not in groupAllowFrom", async () => {
extensions/zalouser/src/monitor.ts+9 −5 modified@@ -311,6 +311,7 @@ async function processMessage( }); const groups = account.config.groups ?? {}; + const routeAllowlistConfigured = Object.keys(groups).length > 0; const allowNameMatching = isDangerousNameMatchingEnabled(account.config); if (isGroup) { const groupEntry = findZalouserGroupEntry( @@ -325,7 +326,7 @@ async function processMessage( ); const routeAccess = evaluateGroupRouteAccessForPolicy({ groupPolicy, - routeAllowlistConfigured: Object.keys(groups).length > 0, + routeAllowlistConfigured, routeMatched: Boolean(groupEntry), routeEnabled: isZalouserGroupEntryAllowed(groupEntry), }); @@ -350,10 +351,13 @@ async function processMessage( const dmPolicy = account.config.dmPolicy ?? "pairing"; const configAllowFrom = (account.config.allowFrom ?? []).map((v) => String(v)); const configGroupAllowFrom = (account.config.groupAllowFrom ?? []).map((v) => String(v)); - const senderGroupPolicy = resolveSenderScopedGroupPolicy({ - groupPolicy, - groupAllowFrom: configGroupAllowFrom, - }); + const senderGroupPolicy = + routeAllowlistConfigured && configGroupAllowFrom.length === 0 + ? groupPolicy + : resolveSenderScopedGroupPolicy({ + groupPolicy, + groupAllowFrom: configGroupAllowFrom, + }); const shouldComputeCommandAuth = core.channel.commands.shouldComputeCommandAuthorized( commandBody, config,
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- github.com/openclaw/openclaw/commit/e64a881ae0fb8af18e451163f4c2d611d60cc8e4nvdPatchWEB
- github.com/advisories/GHSA-63mg-xp9j-jfcmghsaADVISORY
- github.com/openclaw/openclaw/security/advisories/GHSA-63mg-xp9j-jfcmnvdVendor AdvisoryWEB
- nvd.nist.gov/vuln/detail/CVE-2026-33578ghsaADVISORY
- www.vulncheck.com/advisories/openclaw-sender-policy-allowlist-bypass-via-policy-downgrade-in-google-chat-and-zalouser-extensionsnvdThird Party AdvisoryWEB
News mentions
0No linked articles in our index yet.