Medium severity4.3NVD Advisory· Published Apr 23, 2026· Updated Apr 28, 2026
CVE-2026-41350
CVE-2026-41350
Description
OpenClaw before 2026.3.31 contains a session visibility bypass vulnerability where the session_status function fails to enforce configured tools.sessions.visibility restrictions for unsandboxed invocations. Attackers can invoke session_status without sandbox constraints to bypass session-policy controls and access restricted session information.
Affected products
1Patches
14d369a3400dcharden session-status tool visibility guard for all callers
2 files changed · +54 −10
src/agents/openclaw-tools.session-status.test.ts+41 −0 modified@@ -731,6 +731,47 @@ describe("session_status tool", () => { expect(updateSessionStoreMock).not.toHaveBeenCalled(); }); + it("blocks unsandboxed same-agent bare main session_status outside self visibility", async () => { + resetSessionStore({ + "agent:main:main": { + sessionId: "s-parent", + updatedAt: 10, + providerOverride: "anthropic", + modelOverride: "claude-sonnet-4-6", + }, + "agent:main:subagent:child": { + sessionId: "s-child", + updatedAt: 20, + }, + }); + mockConfig = { + session: { mainKey: "main", scope: "per-sender" }, + tools: { + sessions: { visibility: "self" }, + agentToAgent: { enabled: true, allow: ["*"] }, + }, + agents: { + defaults: { + model: { primary: "openai/gpt-5.4" }, + models: {}, + }, + }, + }; + + const tool = getSessionStatusTool("agent:main:subagent:child"); + + await expect( + tool.execute("call-self-visibility-bare-main", { + sessionKey: "main", + model: "default", + }), + ).rejects.toThrow( + "Session status visibility is restricted to the current session (tools.sessions.visibility=self).", + ); + + expect(updateSessionStoreMock).not.toHaveBeenCalled(); + }); + it("blocks unsandboxed same-agent session_status outside tree visibility before mutation", async () => { resetSessionStore({ "agent:main:main": {
src/agents/tools/session-status-tool.ts+13 −10 modified@@ -233,7 +233,7 @@ export function createSessionStatusTool(opts?: { const requesterAgentId = resolveAgentIdFromSessionKey( opts?.agentSessionKey ?? effectiveRequesterKey, ); - const visibilityRequesterKey = effectiveRequesterKey.trim(); + const visibilityRequesterKey = (opts?.agentSessionKey ?? effectiveRequesterKey).trim(); const usesLegacyMainAlias = alias === mainKey; const isLegacyMainVisibilityKey = (sessionKey: string) => { const trimmed = sessionKey.trim(); @@ -282,7 +282,8 @@ export function createSessionStatusTool(opts?: { const requestedKeyParam = readStringParam(params, "sessionKey"); let requestedKeyRaw = requestedKeyParam ?? opts?.agentSessionKey; - let resolvedTargetViaSessionId = false; + const requestedKeyInput = requestedKeyRaw?.trim() ?? ""; + let resolvedViaSessionId = false; if (!requestedKeyRaw?.trim()) { throw new Error("sessionKey required"); } @@ -357,7 +358,7 @@ export function createSessionStatusTool(opts?: { } // If resolution points at another agent, enforce A2A policy before switching stores. ensureAgentAccess(resolveAgentIdFromSessionKey(visibleSession.key)); - resolvedTargetViaSessionId = true; + resolvedViaSessionId = true; requestedKeyRaw = visibleSession.key; agentId = resolveAgentIdFromSessionKey(visibleSession.key); storePath = resolveStorePath(cfg.session?.store, { agentId }); @@ -395,13 +396,15 @@ export function createSessionStatusTool(opts?: { throw new Error(`Unknown ${kind}: ${requestedKeyRaw}`); } - if (resolvedTargetViaSessionId || (opts?.sandboxed === true && !isExplicitAgentKey)) { - const access = visibilityGuard.check( - normalizeVisibilityTargetSessionKey(resolved.key, agentId), - ); - if (!access.allowed) { - throw new Error(access.error); - } + // Preserve caller-scoped raw-key/current lookups as "self" for visibility checks. + const visibilityTargetKey = + !resolvedViaSessionId && + (requestedKeyInput === "current" || resolved.key === requestedKeyInput) + ? visibilityRequesterKey + : normalizeVisibilityTargetSessionKey(resolved.key, agentId); + const access = visibilityGuard.check(visibilityTargetKey); + if (!access.allowed) { + throw new Error(access.error); } const configured = resolveDefaultModelForAgent({ cfg, agentId });
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
3- github.com/openclaw/openclaw/commit/4d369a3400dc9b737fbe8daa63f09d909ce7beb8nvdPatch
- github.com/openclaw/openclaw/security/advisories/GHSA-fwjq-xwfj-gv75nvdVendor Advisory
- www.vulncheck.com/advisories/openclaw-session-visibility-bypass-via-session-status-in-unsandboxed-invocationsnvdThird Party Advisory
News mentions
0No linked articles in our index yet.