← Back to PRs

#11794: fix(gateway): validate session key ownership against authenticated identity

by coygeek open 2026-02-08 09:50 View on GitHub →
gateway stale
## Fix Summary Validates that explicit session keys (via `x-openclaw-session-key` header or request body `sessionKey` field) belong to the authenticated user identity. In multi-user deployments (Tailscale Serve), any authenticated user could previously read/write another user's conversation history, memories, and tool execution context by supplying a predictable session key. ## Issue Linkage Fixes #11793 ## Security Snapshot - CVSS v3.1: 8.1 (High) - CVSS v4.0: 8.6 (High) ## Implementation Details ### Files Changed - `src/gateway/hooks.ts` (+12/-4) - `src/gateway/http-utils.ts` (+26/-1) - `src/gateway/openai-http.ts` (+2/-1) - `src/gateway/openresponses-http.ts` (+7/-1) - `src/gateway/tools-invoke-http.ts` (+17/-1) ### Technical Analysis **`src/gateway/http-utils.ts`** - Add `sessionKeyBelongsToUser()` helper that checks whether a session key contains the authenticated user's identity - Add `authUser` parameter to `resolveSessionKey()` — when set (Tailscale auth), ignores explicit session keys that don't match the authenticated identity and falls through to generate a user-bound key **`src/gateway/openai-http.ts` / `src/gateway/openresponses-http.ts`** - Thread `authResult.user` through to `resolveSessionKey()` via the wrapper functions **`src/gateway/tools-invoke-http.ts`** - Validate body-supplied session keys against `authResult.user` — return 403 if the key belongs to a different user **`src/gateway/hooks.ts`** - Restrict `normalizeAgentPayload()` to the `hook:` namespace — reject session keys starting with `agent:` to prevent hooks from accessing user conversation sessions ## Validation Evidence - Command: `pnpm build` - Status: failed ## Risk and Compatibility - **Single-user deployments**: No change — token/password auth doesn't set `authUser`, so explicit session keys continue to work - **Multi-user Tailscale deployments**: Users can still set explicit session keys that match their own identity. Cross-user access is blocked. - **Hooks**: Hook callers that previously used `agent:` scoped session keys will receive an error. This is intentional — hooks should use the `hook:` namespace. Fixes #11793 ## AI-Assisted Disclosure Generated with [Claude Code](https://claude.ai/code) This fix was generated with AI assistance (Claude Opus 4.6). <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> I’m going to review the PR diff for the 5 changed gateway files, trace how `authResult.user` and session keys flow through request handling (OpenAI/OpenResponses/tools/hooks), and look specifically for any logic gaps that would still allow cross-user session access or unintended breakage (e.g., incorrect session key parsing/ownership checks, inconsistent enforcement across endpoints, or namespace validation errors). I’ll leave only concrete, must-fix issues with exact file+line references. <h3>Confidence Score: 2/5</h3> - This PR improves security posture but still leaves a concrete cross-user session access bypass in the new ownership check logic. - Core change relies on substring matching for session ownership, which is trivially satisfiable by crafting a session key containing the authenticated user marker anywhere in the string. Hook session key restriction also doesn’t fully enforce the intended namespace boundary. These issues affect the primary security objective of the PR. - src/gateway/http-utils.ts (sessionKeyBelongsToUser), src/gateway/hooks.ts (session key namespace enforcement) <!-- greptile_other_comments_section --> **Context used:** - Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8)) - Context from `dashboard` - AGENTS.md ([source](https://app.greptile.com/review/custom-context?memory=0d0c8278-ef8e-4d6c-ab21-f5527e322f13)) <!-- /greptile_comment -->

Most Similar PRs