Unauthenticated POST /api/reset-password and /api/reset-account were a
remotely exploitable auth-bypass on public-facing deployments. The confirm
phrase was embedded in the frontend and echoed back by the API, so it was
friction, not authentication: anyone who knew the account email could reset
the password, log in, and obtain a valid JWT.
Recovery now runs as local CLI commands that operate directly on the database
without starting the HTTP server:
nofx reset-password --email you@example.com
nofx reset-account
These require shell/file access to the host, which a remote attacker does not
have, so recovery stays safe even when NOFX is exposed to the public internet.
- cli.go: new reset-password / reset-account subcommands (hidden password
input on a TTY, --password/stdin for scripting, min 8 chars)
- main.go: dispatch subcommands before the server starts (backward compatible
with the legacy `nofx <dbpath>` arg)
- api: remove public /reset-password and /reset-account routes, their handlers,
and the public confirm-phrase constants
- web: replace the self-service reset form with CLI instructions; drop the
AuthContext resetPassword call and the LoginPage reset-account call (en/zh/id)
- telegram: refresh the bot allowlist comment