From 600976ad873a0c98b67d738aac13a6ae1b9eafec Mon Sep 17 00:00:00 2001 From: Tanuj Date: Wed, 29 Jul 2026 15:40:53 +1000 Subject: [PATCH 1/3] Expand commonPasswordBaseWords with common weak passwords --- application/common/testing/constants.ts | 75 ++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/application/common/testing/constants.ts b/application/common/testing/constants.ts index 738607da..0e186c30 100644 --- a/application/common/testing/constants.ts +++ b/application/common/testing/constants.ts @@ -102,4 +102,77 @@ export const MIME_TYPES: Record = { // csv: 'text/csv' } -export const commonPasswordBaseWords = ['Password', 'Changeme', 'Welcome'] +export const commonPasswordBaseWords = [ + // Numeric sequences + '000000', + '111111', + '1111111', + '11111111', + '112233', + '123123', + '123321', + '12345', + '123456', + '1234567', + '12345678', + '123456789', + '1234567890', + '12345678910', + '555555', + '654321', + '666666', + '7777777', + '987654321', + + // Common words used as passwords + 'Abc123', + 'Admin', + 'Ashley', + 'Bailey', + 'Baseball', + 'Changeme', + 'Dragon', + 'Football', + 'Google', + 'Iloveyou', + 'Jesus', + 'Letmein', + 'Master', + 'Michael', + 'Monkey', + 'Mustang', + 'Mynoob', + 'Ninja', + 'Password', + 'Qwerty', + 'Secret', + 'Shadow', + 'Sunshine', + 'Superman', + 'Trustno1', + 'Welcome', + + // Compound and modified patterns + 'Aa123456', + 'Aa@123456', + 'Admin123', + 'Admin@123', + 'Admintelecom', + 'P@ssw0rd', + 'Pass@123', + 'Passw0rd', + 'Password1', + + // Keyboard walks and bot-observed patterns + '123qwe', + '18atcskd2w', + '1q2w3e', + '1q2w3e4r', + '1q2w3e4r5t', + '3rjs1la7qe', + 'Qazwsx', + 'Qwerty1', + 'Qwerty123', + 'Qwertyuiop', + 'Zxcvbnm', +] From da9392c01cb4aff1b7bfa334a91b7c79091298d3 Mon Sep 17 00:00:00 2001 From: Tanuj Date: Wed, 29 Jul 2026 17:34:24 +1000 Subject: [PATCH 2/3] Show specific matched word in weak-password error --- application/admin-client/cypress/e2e/passwordReset.cy.js | 2 +- application/common/src/PasswordStrength.ts | 5 +++-- application/user-client/cypress/e2e/registration.cy.js | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/application/admin-client/cypress/e2e/passwordReset.cy.js b/application/admin-client/cypress/e2e/passwordReset.cy.js index d5568b98..fdfd7c6a 100644 --- a/application/admin-client/cypress/e2e/passwordReset.cy.js +++ b/application/admin-client/cypress/e2e/passwordReset.cy.js @@ -38,7 +38,7 @@ describe('Password Reset', () => { cy.get('input[id="password"]').type('Testpassword1') cy.get('input[id="confirmPassword"]').type('Testpassword1{enter}') cy.contains('Invalid password').should('exist') - cy.contains('must not contain easily guessable').should('exist') + cy.contains('commonly used weak pattern').should('exist') }) it('opens password reset page and enters non-matching passwords', () => { diff --git a/application/common/src/PasswordStrength.ts b/application/common/src/PasswordStrength.ts index a105e29d..a0ccb937 100644 --- a/application/common/src/PasswordStrength.ts +++ b/application/common/src/PasswordStrength.ts @@ -20,9 +20,10 @@ export function checkPasswordStrength(password: string): PasswordStrengthResult if (password.length < 14) { fields.Length = { message: 'Password must be at least 14 characters' } } - if (baseWordRegex.test(password)) { + const commonMatch = password.match(baseWordRegex) + if (commonMatch) { fields.CommonBase = { - message: `Password must not contain easily guessable words (i.e. ${commonPasswordBaseWords.join(', ')})`, + message: `Password contains a commonly used weak pattern: "${commonMatch[0]}". Please choose something less predictable.`, } } if (!/[A-Z]/.test(password)) { diff --git a/application/user-client/cypress/e2e/registration.cy.js b/application/user-client/cypress/e2e/registration.cy.js index 579d03a0..ecc8e023 100644 --- a/application/user-client/cypress/e2e/registration.cy.js +++ b/application/user-client/cypress/e2e/registration.cy.js @@ -90,7 +90,7 @@ describe('registration', () => { cy.get('[data-cy="reg-confirm-password"]').type('Testpassword1') cy.get('[data-cy="reg-button"]').click() cy.contains('Invalid password').should('exist') - cy.contains('must not contain easily guessable words').should('exist') + cy.contains('commonly used weak pattern').should('exist') }) it('Attempt to register existing email (i.e. no invite) and get correct error message', () => { From d07ef841c2c936cffc1cc293e4e2b5a9052e0e6b Mon Sep 17 00:00:00 2001 From: Tanuj Date: Wed, 29 Jul 2026 18:05:00 +1000 Subject: [PATCH 3/3] Update test admin passwords to avoid new blocklist substring The admin test users all used 'Loginforadmin1' which now contains 'admin' as a blocked substring after this PR's blocklist expansion, causing integration tests to fail on registration. Switched to 'Loginfortests123' which matches the pattern already used by other tests and passes all current checks. --- application/common/testing/constants.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/application/common/testing/constants.ts b/application/common/testing/constants.ts index 0e186c30..f444ccaa 100644 --- a/application/common/testing/constants.ts +++ b/application/common/testing/constants.ts @@ -4,17 +4,17 @@ export const TestUsers = { OPERATOR_ADMIN: { email: 'operatoradmin@example.com', - password: 'Loginforadmin1', + password: 'Loginfortests123', id: 96, }, ORG_ADMIN: { email: 'admin@example.com', - password: 'Loginforadmin1', + password: 'Loginfortests123', id: 97, }, ORG_ADMIN_2: { email: 'admin2@example.com', - password: 'Loginforadmin1', + password: 'Loginfortests123', id: 101, }, PARTICIPANT_UNANSWERED: { @@ -37,7 +37,7 @@ export const TestUsers = { }, STUDY_ADMIN: { email: 'studyadmin@example.com', - password: 'Loginforadmin1', + password: 'Loginfortests123', id: 106, }, PASSWORD_RESET_USER: {