Default root-password warning checks the wrong password
Summary
The first-run root account is created with the default password chatnio123456, and the README also tells operators to log in with root / chatnio123456. However, the frontend warning that asks operators to change the default root password checks for coai123456 instead.
As a result, an operator who logs in with the actual default password may not see the intended warning to rotate it.
Evidence
The backend creates the first root user with chatnio123456:
103 func InitRootUser(db *sql.DB) {
104 // create root user if totally empty
105 var count int
106 err := globals.QueryRowDb(db, "SELECT COUNT(*) FROM auth").Scan(&count)
107 if err != nil {
108 globals.Warn(fmt.Sprintf("[service] failed to query user count: %s", err.Error()))
109 return
110 }
111
112 if count == 0 {
113 globals.Debug("[service] no user found, creating root user (username: root, password: chatnio123456, email: [email protected])")
114 _, err := globals.ExecDb(db, `
115 INSERT INTO auth (username, password, email, is_admin, bind_id, token)
116 VALUES (?, ?, ?, ?, ?, ?)
117 `, "root", utils.Sha2Encrypt("chatnio123456"), "[email protected]", true, 0, "root")The README tells operators the same default password:
86 ## Deployment
87 > [!TIP]
88 > **After successful deployment, the admin account is `root`, with the default password `chatnio123456`**
89
90 ### ✨ Zeabur (One-Click)
91 [](https://zeabur.com/templates/M86XJI)
92
93 > Zeabur provides a certain free quota, you can use non-paid regions for one-click deployment, and also supports plan subscriptions and elastic billing for flexible expansion.
94 > 1. Click `Deploy` to deploy, and enter the domain name you wish to bind, wait for the deployment to complete.
95 > 2. After deployment is complete, please visit your domain name and log in to the backend management using the username `root` and password `chatnio123456`. Please follow the prompts to change the password in the chatnio backend in a timely manner.But the frontend default-password warning checks a different value:
108 toast.success(t("login-success"), {
109 description: t("login-success-prompt"),
110 });
111
112 if (
113 form.username.trim() === "root" &&
114 form.password.trim() === "coai123456"
115 ) {
116 toast.warning(t("admin.default-password"), {
117 description: t("admin.default-password-prompt"),
118 duration: 15000,
119 });
120 }Why this matters
CoAI is an LLM gateway/admin system. The root admin account controls sensitive gateway state such as channels, upstream credentials, model routing, pricing, quota, and user/API-key management. A missed default-password warning increases the chance that a newly deployed instance keeps a public, documented administrator password longer than intended.
Suggested fix
At minimum, update the frontend check to match the actual default password:
form.password.trim() === "chatnio123456"Longer term, a safer pattern would be to avoid hardcoded default credentials entirely, for example:
- generate a random first-run root password and print it once to the operator;
- require setting the initial root password through an environment variable;
- force a password change after the first login when the account was bootstrap-created.
Source: coaidev/coai