diff --git a/.changeset/cognito-prevent-user-enumeration.md b/.changeset/cognito-prevent-user-enumeration.md new file mode 100644 index 00000000..841628cf --- /dev/null +++ b/.changeset/cognito-prevent-user-enumeration.md @@ -0,0 +1,5 @@ +--- +"@aws-blocks/bb-auth-cognito": patch +--- + +Enable `PreventUserExistenceErrors` on the Cognito user pool client. Sign-in and forgot-password responses now return a uniform error regardless of whether the username exists, closing the account-enumeration oracle that Cognito exposes by default (distinct `UserNotFoundException` vs. wrong-password errors). diff --git a/packages/bb-auth-cognito/README.md b/packages/bb-auth-cognito/README.md index 78fa45c8..14b30200 100644 --- a/packages/bb-auth-cognito/README.md +++ b/packages/bb-auth-cognito/README.md @@ -521,6 +521,8 @@ Cognito scales automatically. Default quotas: 40 sign-ups/sec, 120 sign-ins/sec AWS Blocks auth follows the BFF pattern: the browser sends `{username, password}` to the customer's Lambda over TLS; Lambda forwards to Cognito. The customer's Lambda is inside the user's trust boundary by design — same as `AuthBasic`, `AuthOIDC`, NextAuth, Devise, and every server-mediated auth library. Cognito tokens never reach the browser — instead, the BB issues an opaque HMAC-signed session cookie that maps to a server-side `SessionRecord` in a nested `KVStore`. +The user pool client sets `PreventUserExistenceErrors: ENABLED`, so sign-in and forgot-password responses return a uniform error whether or not the username exists — closing the account-enumeration oracle Cognito exposes by default. + See the auth-cognito technical design (see source repo) for the full architecture and mock-vs-AWS parity notes. ## Cookies and sessions diff --git a/packages/bb-auth-cognito/src/index.cdk.test.ts b/packages/bb-auth-cognito/src/index.cdk.test.ts index 871b8b41..ee4e29a1 100644 --- a/packages/bb-auth-cognito/src/index.cdk.test.ts +++ b/packages/bb-auth-cognito/src/index.cdk.test.ts @@ -132,6 +132,15 @@ describe('AuthCognito (CDK) — user pool client', () => { }); }); + test('client enables PreventUserExistenceErrors (no username enumeration oracle)', () => { + const template = synth((stack) => { + new AuthCognito(scope(stack), 'auth'); + }); + template.hasResourceProperties('AWS::Cognito::UserPoolClient', { + PreventUserExistenceErrors: 'ENABLED', + }); + }); + test('hosted-UI / OAuth flows are disabled (no implicit grant, no placeholder callback)', () => { const template = synth((stack) => { new AuthCognito(scope(stack), 'auth'); diff --git a/packages/bb-auth-cognito/src/index.cdk.ts b/packages/bb-auth-cognito/src/index.cdk.ts index 5ace421c..f8250c20 100644 --- a/packages/bb-auth-cognito/src/index.cdk.ts +++ b/packages/bb-auth-cognito/src/index.cdk.ts @@ -238,6 +238,12 @@ export class AuthCognito