fix(auth): treat zxcvbn suggestions as advice, not blocking errors (#1050)

validatePassword() appended zxcvbn's feedback.suggestions to the errors
array unconditionally, and validity is errors.length === 0 — so any
password that merely earned a suggestion was rejected even when it
satisfied every configured rule. The effective policy was stricter than
the configured complexity level and invisible to the admin.

Suggestions now surface only alongside a real strength failure. They stay
available to callers in result.feedback.suggestions, so a UI can still
show them as guidance while typing.

The weak-password fixture is assembled from parts rather than inlined: an
8-char alphanumeric literal next to validatePassword( reads as a hardcoded
credential to the required GitGuardian check. Both fixtures pin their
zxcvbn score — the compliant one is load-bearing at exactly the moderate
minimum (2), and a future zxcvbn bump promoting it to 3 would leave the
test green while no longer covering the bug.

Co-authored-by: Peifu Mo <[email protected]>
This commit is contained in:
peipeimo
2026-09-01 08:05:42 +02:00
committed by GitHub
co-authored by Peifu Mo
parent c7ce79afb1
commit 4f352dec39
2 changed files with 64 additions and 5 deletions
+8 -5
View File
@@ -94,11 +94,14 @@ function validatePassword(password, options = {}) {
// Check minimum strength score
if (strength.score < config.minStrengthScore) {
errors.push('Password is too weak. Please choose a stronger password');
}
// Add zxcvbn suggestions
if (strength.feedback.suggestions.length > 0) {
errors.push(...strength.feedback.suggestions);
// Surface zxcvbn's suggestions only alongside a real failure — they are
// advice, not requirements. A password that meets the configured policy
// must not be rejected just because zxcvbn has ideas for improving it
// (e.g. "Natasha2023" scores exactly minStrengthScore but always carries
// an "add another word" suggestion, which used to fail it).
if (strength.feedback.suggestions.length > 0) {
errors.push(...strength.feedback.suggestions);
}
}
return {