VYPR
High severity8.1NVD Advisory· Published Apr 9, 2026· Updated Apr 15, 2026

CVE-2026-35645

CVE-2026-35645

Description

OpenClaw before 2026.3.25 contains a privilege escalation vulnerability in the gateway plugin subagent fallback deleteSession function that uses a synthetic operator.admin runtime scope. Attackers can exploit this by triggering session deletion without a request-scoped client to execute privileged operations with unintended administrative scope.

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
b5d785f1a59a

Gateway: require caller scope for subagent session deletion (#55281)

https://github.com/openclaw/openclawJacob TomlinsonMar 26, 2026via ghsa
2 files changed · +51 14
  • src/gateway/server-plugins.test.ts+47 4 modified
    @@ -470,16 +470,59 @@ describe("loadGatewayPlugins", () => {
         expect(getLastDispatchedClientScopes()).not.toContain("operator.admin");
       });
     
    -  test("keeps admin scope for fallback session deletion", async () => {
    +  test("rejects fallback session deletion without minting admin scope", async () => {
         const serverPlugins = serverPluginsModule;
         const runtime = await createSubagentRuntime(serverPlugins);
         serverPlugins.setFallbackGatewayContext(createTestContext("synthetic-delete-session"));
     
    -    await runtime.deleteSession({
    -      sessionKey: "s-delete",
    -      deleteTranscript: true,
    +    handleGatewayRequest.mockImplementationOnce(async (opts: HandleGatewayRequestOptions) => {
    +      // Re-run the gateway scope check here so the test proves fallback dispatch
    +      // does not smuggle admin into the request client.
    +      const scopes = Array.isArray(opts.client?.connect?.scopes) ? opts.client.connect.scopes : [];
    +      const auth = methodScopesModule.authorizeOperatorScopesForMethod("sessions.delete", scopes);
    +      if (!auth.allowed) {
    +        opts.respond(false, undefined, {
    +          code: "INVALID_REQUEST",
    +          message: `missing scope: ${auth.missingScope}`,
    +        });
    +        return;
    +      }
    +      opts.respond(true, {});
         });
     
    +    await expect(
    +      runtime.deleteSession({
    +        sessionKey: "s-delete",
    +        deleteTranscript: true,
    +      }),
    +    ).rejects.toThrow("missing scope: operator.admin");
    +
    +    expect(getLastDispatchedClientScopes()).toEqual(["operator.write"]);
    +    expect(getLastDispatchedClientScopes()).not.toContain("operator.admin");
    +  });
    +
    +  test("allows session deletion when the request scope already has admin", async () => {
    +    const serverPlugins = serverPluginsModule;
    +    const runtime = await createSubagentRuntime(serverPlugins);
    +    const scope = {
    +      context: createTestContext("request-scope-delete-session"),
    +      client: {
    +        connect: {
    +          scopes: ["operator.admin"],
    +        },
    +      } as GatewayRequestOptions["client"],
    +      isWebchatConnect: () => false,
    +    } satisfies PluginRuntimeGatewayRequestScope;
    +
    +    await expect(
    +      gatewayRequestScopeModule.withPluginRuntimeGatewayRequestScope(scope, () =>
    +        runtime.deleteSession({
    +          sessionKey: "s-delete-admin",
    +          deleteTranscript: true,
    +        }),
    +      ),
    +    ).resolves.toBeUndefined();
    +
         expect(getLastDispatchedClientScopes()).toEqual(["operator.admin"]);
       });
     
    
  • src/gateway/server-plugins.ts+4 10 modified
    @@ -367,16 +367,10 @@ export function createGatewaySubagentRuntime(): PluginRuntime["subagent"] {
           return getSessionMessages(params);
         },
         async deleteSession(params) {
    -      await dispatchGatewayMethod(
    -        "sessions.delete",
    -        {
    -          key: params.sessionKey,
    -          deleteTranscript: params.deleteTranscript ?? true,
    -        },
    -        {
    -          syntheticScopes: [ADMIN_SCOPE],
    -        },
    -      );
    +      await dispatchGatewayMethod("sessions.delete", {
    +        key: params.sessionKey,
    +        deleteTranscript: params.deleteTranscript ?? true,
    +      });
         },
       };
     }
    

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.