You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Three high-confidence auth gaps fixed after a focused review following a
user report that admin/admin on the public demo returned a fully usable
admin JWT.
- get_current_user now enforces must_change_password server-side. Only
/api/auth/me and /api/auth/change-password are allowed while the flag
is set; every other endpoint returns 403. Previously the flag was only
surfaced by the UI modal, which a direct API caller could ignore.
- Pre-2FA 'temp_token' was broken: create_access_token silently ignored
the 'exp_minutes' key and minted a full 24h session JWT, and no
endpoint looked at the pending_2fa claim, so the temp token bypassed
2FA entirely. Fixed by adding an 'expires_minutes' parameter (now 2
minutes) and rejecting pending_2fa=True tokens everywhere except
/api/auth/login itself.
- API key auth now honors must_change_password (403 if the owning user
is in forced-change state). Prevents working around the lockout by
minting a key before changing the password.
- /api/recordings/{id}/play HTML now sends Referrer-Policy: no-referrer
and Cache-Control: private, no-store, and the asciinema-player CDN
assets are fetched with referrerpolicy='no-referrer', so the ?token=
in the URL no longer leaks to third parties.
Verified end-to-end: admin/admin JWT now 403s on /api/auth/users and
/api/servers but works on /api/auth/me; after POST /api/auth/change-
password the same account receives a normal token that passes every
check. Temp token from the pre-2FA step returns 403 'Pending 2FA' on
every endpoint.
Docs: README screenshot sub-sections renamed from release-pack labels
to functional titles (jump host / snippets / shared terminal / session
recording / demo mode).
Copy file name to clipboardExpand all lines: CHANGELOG.md
+17Lines changed: 17 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,22 @@
1
1
# Changelog
2
2
3
+
## v0.5.1 (2026-04-16) — Security hotfix
4
+
5
+
### Security (please upgrade)
6
+
7
+
Three authentication gaps fixed after a focused security review.
8
+
9
+
-**`must_change_password` is now enforced server-side**. Previously the flag was only surfaced by the UI; a valid JWT from a `admin/admin` first-run login let attackers hit every admin endpoint (`/api/auth/users`, `/api/servers`, audit log, ...) without ever changing the password. `get_current_user` now returns `403 Password change required` for any path other than `/api/auth/me` and `/api/auth/change-password` while the flag is `True`. *(Credit: user report on the public demo.)*
10
+
-**Pre-2FA "temp token" is now truly short-lived and scoped.** The `create_access_token({"pending_2fa": True, "exp_minutes": 2})` call ignored `exp_minutes` — the token got the full 24-hour session TTL, and no endpoint checked the `pending_2fa` claim, so the "temp" token bypassed 2FA completely. Fixed by: adding `expires_minutes` parameter to `create_access_token`, setting it to 2, and rejecting any token with `pending_2fa=True` on every endpoint except `/api/auth/login` itself.
11
+
-**API keys cannot bypass forced password change.** An account with `must_change_password=True` can no longer create or use an API key until the password has been rotated. Prevents workaround paths when an admin issues a temporary password.
12
+
-**Recording replay page no longer leaks the session token via Referer.**`GET /api/recordings/{id}/play` now sends `Referrer-Policy: no-referrer` and `Cache-Control: private, no-store`, and all third-party assets on the page (asciinema-player CDN) are fetched with `referrerpolicy="no-referrer"`.
13
+
14
+
### Docs
15
+
16
+
- README: screenshot sub-sections renamed to functional titles (jump host / snippets / shared terminal / session recording / demo mode) instead of release-pack labels, so the README always describes what the current version ships.
|  |  |
162
+
|  |  |
`WEBGATE_DEMO_MODE=true` turns the app into a sandbox: banner, seeded `demo`/`demo` user, all writes blocked. Used by the live demo at [webgate-demo.fly.dev](https://webgate-demo.fly.dev/).
[`compose.ha.yml`](compose.ha.yml) spins up 2 webgate replicas + Postgres + nginx with `ip_hash` sticky sessions. On leader loss, the lease expires within 90 seconds and another replica picks it up automatically.
553
564
554
-
> **Known limitation**: live shared-terminal sessions still need owner and joiner on the same worker. Sticky sessions mitigate it for same-browser joins; true cross-worker fan-out needs Redis pub/sub — planned for a later v0.5.x.
565
+
> **Known limitation**: live shared-terminal sessions still need owner and joiner on the same worker. Sticky sessions mitigate it for same-browser joins; true cross-worker fan-out requires a Redis pub/sub layer (not yet implemented).
0 commit comments