diff --git a/packages/ui-extensions-server-kit/src/ExtensionServerClient/ExtensionServerClient.test.ts b/packages/ui-extensions-server-kit/src/ExtensionServerClient/ExtensionServerClient.test.ts index 8ef4ffa1aea..d12ef00ed29 100644 --- a/packages/ui-extensions-server-kit/src/ExtensionServerClient/ExtensionServerClient.test.ts +++ b/packages/ui-extensions-server-kit/src/ExtensionServerClient/ExtensionServerClient.test.ts @@ -188,6 +188,28 @@ describe('ExtensionServerClient', () => { expect(client.connection).toBeUndefined() expect(mockSocketServer.clients.length).toBe(0) }) + + test('uses crypto.randomUUID for id generation when available', () => { + const uuid = '12345678-1234-1234-1234-123456789012' + vi.stubGlobal('crypto', { + randomUUID: () => uuid, + }) + + const client = new ExtensionServerClient() + expect(client.id).toBe(uuid) + + vi.unstubAllGlobals() + }) + + test('falls back to Math.random for id generation when crypto.randomUUID is not available', () => { + vi.stubGlobal('crypto', undefined) + + const client = new ExtensionServerClient() + expect(client.id).toBeDefined() + expect(client.id.length).toBeGreaterThan(0) + + vi.unstubAllGlobals() + }) }) describe('on()', () => { diff --git a/packages/ui-extensions-server-kit/src/ExtensionServerClient/ExtensionServerClient.ts b/packages/ui-extensions-server-kit/src/ExtensionServerClient/ExtensionServerClient.ts index 507bfb5df73..4a568d8a23d 100644 --- a/packages/ui-extensions-server-kit/src/ExtensionServerClient/ExtensionServerClient.ts +++ b/packages/ui-extensions-server-kit/src/ExtensionServerClient/ExtensionServerClient.ts @@ -32,7 +32,11 @@ export class ExtensionServerClient implements ExtensionServer.Client { private uiExtensionsByUuid: Record = {} constructor(options: DeepPartial = {}) { - this.id = (Math.random() + 1).toString(36).substring(7) + // We use a CSPRNG for ID generation where available to prevent predictability. + this.id = + typeof globalThis.crypto?.randomUUID === 'function' + ? globalThis.crypto.randomUUID() + : (Math.random() + 1).toString(36).substring(7) this.options = getValidatedOptions({ ...options, connection: {