mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2026-09-03 07:24:52 +08:00
A demo visitor could change the admin password and lock everyone out. The chain: demo mode refuses TOTP enrollment (api/user/otp.go), so userNeedsSecureSession() is false, so RequireSecureSession() passes through, and POST /api/user/password had no demo guard of its own. Everything else with an effect outside the container was open for the same reason: ACME issuance against a real CA, backup archives carrying the crypto secret, outbound webhooks, DNS provider mutations, service token minting, and a site health check whose request body chooses the outbound destination. Until now the only thing preventing any of it was that docker-compose-demo.yml disables outbound NAT. Add RejectInDemo()/DemoReadOnly() and attach them to those routes. Local CRUD stays open: the demo runs on ephemeral disk and restores itself, so creating a site is a feature rather than a risk. Note these guards are not redundant with RequireSecureSession — that middleware is inert for a user with no OTP, 2FA or passkey, which on a demo node is every user. Also move the middleware error scope into its own errors.go: the errdef generator resolves a scope per file, so errors declared alongside a scope defined elsewhere were silently missing from the generated frontend constants. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>