← Dev log
EduQate·infrastructure·2026-08-23

Maintenance mode that in-app browsers walked past

Maintenance mode was enforced in a React component that renders after a successful poll, so in-app browsers (Messenger, Instagram) walked straight past it into the normal app.

Only visible by using it

Invisible to a code read. Found by being the real user, on a real device, at a real width.

With maintenance mode on, a normal browser showed the maintenance screen and an embedded browser (Messenger, Instagram) rendered the normal app with no data.

The flag is enforced on the API, but the screen is a React component that only renders after a successful poll — so enforcement of a platform-wide block lived entirely in client-side JS that had to complete a cross-origin fetch to know to block itself. Any client where that fetch quietly fails renders the ordinary shell forever.

Moved it to the edge: a @Public() gate route deliberately left off the guard's allow-list, so the existing guard produces the 503 with no new logic; Caddy checks it server-to-server on real page navigations only and promotes a non-2xx into error 503, which flows into the handle_errors block already serving the branded page. Super-admin's own hostname is excluded, or you lock yourself out of the switch that turns it off.

Caught while testing: an error <message> <status> argument-order mistake produced a 500 instead of the maintenance page. Found by standing up a disposable Caddy container against mock upstreams with the real unmodified Caddyfile, not by reading it. The in-app-browser bypass itself was never reproduced — that needs a real device on the live domain, and the ledger row says so.