From 5cd781bd51ca32a68ba3d6a2ea9b66b5599bf2e1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 18 Jan 2026 11:28:04 +0000 Subject: [PATCH] Replace check-password-strength with NIST-aligned password validation Co-authored-by: CommanderStorm <26258709+CommanderStorm@users.noreply.github.com> --- extra/reset-password.js | 12 ++++++----- package.json | 1 - server/password-util.js | 47 +++++++++++++++++++++++++++++++++++++++++ server/server.js | 8 ++++--- src/lang/en.json | 2 +- 5 files changed, 60 insertions(+), 10 deletions(-) create mode 100644 server/password-util.js diff --git a/extra/reset-password.js b/extra/reset-password.js index 29aad642f..1d03adb41 100644 --- a/extra/reset-password.js +++ b/extra/reset-password.js @@ -3,7 +3,7 @@ console.log("== Uptime Kuma Reset Password Tool =="); const Database = require("../server/database"); const { R } = require("redbean-node"); const readline = require("readline"); -const { passwordStrength } = require("check-password-strength"); +const { validatePassword } = require("../server/password-util"); const { initJWTSecret } = require("../server/util-server"); const User = require("../server/model/user"); const { io } = require("socket.io-client"); @@ -46,13 +46,15 @@ const main = async () => { "Warning: the password might be stored, in plain text, in your shell's history" ); password = confirmPassword = args["new-password"] + ""; - if (passwordStrength(password).value === "Too weak") { - throw new Error("Password is too weak, please use a stronger password."); + const passwordValidation = validatePassword(password); + if (!passwordValidation.ok) { + throw new Error(passwordValidation.msg || "Password is too weak, please use a stronger password."); } } else { password = await question("New Password: "); - if (passwordStrength(password).value === "Too weak") { - console.log("Password is too weak, please try again."); + const passwordValidation = validatePassword(password); + if (!passwordValidation.ok) { + console.log(passwordValidation.msg || "Password is too weak, please try again."); continue; } confirmPassword = await question("Confirm New Password: "); diff --git a/package.json b/package.json index 23f4d26ee..f6c2ed1e3 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,6 @@ "badge-maker": "~3.3.1", "bcryptjs": "~2.4.3", "chardet": "~1.4.0", - "check-password-strength": "^2.0.5", "cheerio": "~1.0.0-rc.12", "chroma-js": "~2.4.2", "command-exists": "~1.2.9", diff --git a/server/password-util.js b/server/password-util.js new file mode 100644 index 000000000..fe99c99e7 --- /dev/null +++ b/server/password-util.js @@ -0,0 +1,47 @@ +/** + * Password validation utility following NIST SP 800-63B guidelines + * @module password-util + */ + +/** + * Minimum password length as per NIST recommendations + */ +const MIN_PASSWORD_LENGTH = 8; + +/** + * Validates a password according to NIST SP 800-63B guidelines. + * + * NIST guidelines state: + * - Passwords should have a minimum length (8-12 characters recommended) + * - Composition rules (requiring specific character types) SHALL NOT be imposed + * - All printable ASCII characters and Unicode characters should be allowed + * + * This implementation enforces only minimum length, allowing all character compositions. + * + * @param {string} password - The password to validate + * @returns {{ ok: boolean, msg?: string }} Validation result + */ +function validatePassword(password) { + if (!password) { + return { + ok: false, + msg: "Password cannot be empty" + }; + } + + if (password.length < MIN_PASSWORD_LENGTH) { + return { + ok: false, + msg: `Password must be at least ${MIN_PASSWORD_LENGTH} characters long` + }; + } + + return { + ok: true + }; +} + +module.exports = { + validatePassword, + MIN_PASSWORD_LENGTH +}; diff --git a/server/server.js b/server/server.js index 885e88340..755405c7b 100644 --- a/server/server.js +++ b/server/server.js @@ -83,7 +83,7 @@ log.debug("server", "Importing http-graceful-shutdown"); const gracefulShutdown = require("http-graceful-shutdown"); log.debug("server", "Importing prometheus-api-metrics"); const prometheusAPIMetrics = require("prometheus-api-metrics"); -const { passwordStrength } = require("check-password-strength"); +const { validatePassword } = require("./password-util"); const TranslatableError = require("./translatable-error"); log.debug("server", "Importing 2FA Modules"); @@ -683,7 +683,8 @@ let needSetup = false; socket.on("setup", async (username, password, callback) => { try { - if (passwordStrength(password).value === "Too weak") { + const passwordValidation = validatePassword(password); + if (!passwordValidation.ok) { throw new TranslatableError("passwordTooWeak"); } @@ -1416,7 +1417,8 @@ let needSetup = false; throw new Error("Invalid new password"); } - if (passwordStrength(password.newPassword).value === "Too weak") { + const passwordValidation = validatePassword(password.newPassword); + if (!passwordValidation.ok) { throw new TranslatableError("passwordTooWeak"); } diff --git a/src/lang/en.json b/src/lang/en.json index 5bcc6b59a..2220bd827 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -1363,7 +1363,7 @@ "Show this Maintenance Message on which Status Pages": "Show this Maintenance Message on which Status Pages", "Endpoint": "Endpoint", "Details": "Details", - "passwordTooWeak": "Password is too weak. It should contain alphabetic and numeric characters. It must be at least 6 characters in length.", + "passwordTooWeak": "Password must be at least 8 characters long.", "TLS Alerts": "TLS Alerts", "Expected TLS Alert": "Expected TLS Alert", "None (Successful Connection)": "None (Successful Connection)",