From eed9e7206115b567bddd9296de0481e4b7c37f4f Mon Sep 17 00:00:00 2001 From: osama-rizk Date: Mon, 3 Aug 2026 12:25:58 +0200 Subject: [PATCH] fix(bb-auth-cognito): enable PreventUserExistenceErrors on the user pool client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cognito's default user pool client returns a distinct UserNotFoundException for unknown usernames vs. a wrong-password error for known ones, which is an account- enumeration oracle on sign-in and forgot-password. Setting preventUserExistenceErrors: true makes Cognito return a uniform error regardless of whether the username exists. The mock's public sign-in path already returns a uniform NotAuthorized error, so local↔AWS parity holds; the only user-existence-revealing throw is in the privileged admin surface, which is inside the trust boundary by design. Adds a CDK assertion that the synthesized UserPoolClient has PreventUserExistenceErrors: ENABLED (verified red on the prior code). --- .changeset/cognito-prevent-user-enumeration.md | 5 +++++ packages/bb-auth-cognito/README.md | 2 ++ packages/bb-auth-cognito/src/index.cdk.test.ts | 9 +++++++++ packages/bb-auth-cognito/src/index.cdk.ts | 6 ++++++ 4 files changed, 22 insertions(+) create mode 100644 .changeset/cognito-prevent-user-enumeration.md 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