VYPR
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.

PackageAffected versionsPatched versions
openclawnpm
< 2026.3.282026.3.28

Affected products

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

Patches

1
e64a881ae0fb

Channels: preserve routed group policy (#56011)

https://github.com/openclaw/openclawJacob TomlinsonMar 27, 2026via ghsa
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

News mentions

0

No linked articles in our index yet.