fix(browse): unexchanged pair setup keys no longer authenticate bearer requests

validateToken accepted a gsk_setup_ key as a bearer on /command, /batch and
/file (found while building the W3 auth matrix). A setup key now only
authenticates the /connect exchange.
This commit is contained in:
garrytan committed 2026-09-30 06:33:20 +00:00
1 parent f8cd2057e1
commit f1818aec69
2 files changed
+13 -7

No files matched your search

+4 -2
View File
@@ -377,7 +377,9 @@ export function exchangeSetupKey(setupKey: string, sessionExpiresSeconds?: numbe
/**
* Validate a token and return its info if valid.
* Returns null for expired, revoked, or unknown tokens.
* Returns null for expired, revoked, or unknown tokens, and for unexchanged
* setup keys: a setup key authenticates only the /connect exchange, never a
* bearer request.
* Root token returns a special root info object.
*/
export function validateToken(token: string): TokenInfo | null {
@@ -396,7 +398,7 @@ export function validateToken(token: string): TokenInfo | null {
}
const info = tokens.get(token);
if (!info) return null;
if (!info || info.type !== 'session') return null;
// Check expiry
if (info.expiresAt && new Date(info.expiresAt) < new Date()) {
+9 -5
View File
@@ -233,15 +233,19 @@ describe('token-registry', () => {
it('rejects expired setup key', () => {
const setup = createSetupKey({});
// Manually expire it
const info = validateToken(setup.token);
if (info) {
(info as any).expiresAt = new Date(Date.now() - 1000).toISOString();
}
// Manually expire it (createSetupKey returns the registry's own record)
setup.expiresAt = new Date(Date.now() - 1000).toISOString();
const session = exchangeSetupKey(setup.token);
expect(session).toBeNull();
});
it('does not accept an unexchanged setup key as a bearer token', () => {
const setup = createSetupKey({ scopes: ['read', 'write'] });
expect(validateToken(setup.token)).toBeNull();
const session = exchangeSetupKey(setup.token);
expect(validateToken(session!.token)).not.toBeNull();
});
it('rejects unknown setup key', () => {
expect(exchangeSetupKey('gsk_setup_nonexistent')).toBeNull();
});