From 720872a39115ec37e412c4331b7b5175248087bc Mon Sep 17 00:00:00 2001 From: Mark Liu Date: Wed, 4 Mar 2026 12:03:11 +1100 Subject: [PATCH] security: reject known-insecure default passwords during admin seeding (#123) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The admin seeding function previously fell back to password 'admin' when AUTH_PASS was unset, and accepted any value from .env.example including the documented default 'change-me-on-first-login'. This meant a user who copied .env.example without changing the password (or forgot to set AUTH_PASS entirely) would have an instance running with publicly known credentials. The seeding function now: - Skips seeding entirely if AUTH_PASS is not set (instead of defaulting to 'admin') - Checks AUTH_PASS against a blocklist of known insecure values (admin, password, change-me-on-first-login, changeme, testpass123) - Logs a clear warning explaining what to do in both cases Existing instances that already have users in the database are not affected — the seeding function only runs when the users table is empty. Signed-off-by: Mark Liu --- src/lib/db.ts | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/lib/db.ts b/src/lib/db.ts index 6590156..76d5cc7 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -73,6 +73,16 @@ function initializeSchema() { interface CountRow { count: number } +// Known-insecure passwords that should never be used in production. +// Includes the .env.example default and common placeholder values. +const INSECURE_PASSWORDS = new Set([ + 'admin', + 'password', + 'change-me-on-first-login', + 'changeme', + 'testpass123', +]) + function seedAdminUserFromEnv(dbConn: Database.Database): void { // Skip seeding during `next build` — env vars may not be available yet if (process.env.NEXT_PHASE === 'phase-production-build') return @@ -81,7 +91,25 @@ function seedAdminUserFromEnv(dbConn: Database.Database): void { if (count > 0) return const username = process.env.AUTH_USER || 'admin' - const password = process.env.AUTH_PASS || 'admin' + const password = process.env.AUTH_PASS + + if (!password) { + logger.warn( + 'AUTH_PASS is not set — skipping admin user seeding. ' + + 'Set AUTH_PASS in your .env file to create the initial admin account.' + ) + return + } + + if (INSECURE_PASSWORDS.has(password)) { + logger.warn( + `AUTH_PASS matches a known insecure default ("${password}"). ` + + 'Please set a strong, unique password in your .env file. ' + + 'Skipping admin user seeding until credentials are changed.' + ) + return + } + const displayName = username.charAt(0).toUpperCase() + username.slice(1) dbConn.prepare(`