From 804e380dea642b34a6217e72168c1dc5ff6a316d Mon Sep 17 00:00:00 2001 From: Bilal Godil Date: Mon, 8 Jun 2026 11:45:00 -0700 Subject: [PATCH] fix(rde): reject foreign tokens in InternalSession.updateAccessToken Make the "a session never changes which session it belongs to" invariant self-enforcing: only install an access token whose session key matches this session's, so the public method can't be misused to write foreign credentials into the in-memory token cache. --- packages/shared/src/sessions.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/sessions.ts b/packages/shared/src/sessions.ts index 788fc1756..667d3a85a 100644 --- a/packages/shared/src/sessions.ts +++ b/packages/shared/src/sessions.ts @@ -220,8 +220,8 @@ export class InternalSession { /** * Installs a fresh access token into this session in place, keeping the session object (and therefore every - * session-scoped cache) stable instead of constructing a new InternalSession. Caller must pass a token that - * belongs to the same session. No-op if the session is invalid, the token can't be decoded, or it's unchanged; + * session-scoped cache) stable instead of constructing a new InternalSession. No-op if the session is invalid, + * the token can't be decoded, it's unchanged, or it doesn't belong to this session (its session key differs); * never clears an existing token. */ updateAccessToken(accessToken: string | null) { @@ -229,6 +229,10 @@ export class InternalSession { if (!accessToken) return; const newAccessToken = AccessToken.createIfValid(accessToken); if (!newAccessToken) return; + // Self-enforce the "a session never changes which session it belongs to" invariant: only install a token that + // maps to this same session key, so a foreign token can never be written into this object's cache. + const newSessionKey = InternalSession.calculateSessionKey({ refreshToken: this._refreshToken?.token ?? null, accessToken: newAccessToken.token }); + if (newSessionKey !== this.sessionKey) return; if (this._accessToken.get()?.token === newAccessToken.token) return; this._accessToken.set(newAccessToken); }