Private Landing v1.4.0
🛡️ Rate Limiting & Security Hardening
This release adds fixed-window rate limiting across all auth routes, closes an atomicity gap that could cause permanent key lockout, removes an unnecessary 'unsafe-eval' from the CSP, and ships a security audit covering both the rate limiting middleware and the v1.3.0 wizard UI.
What's New
- 🚦 Fixed-Window Rate Limiting
createRateLimitermiddleware backed by theCacheClientabstraction throttles brute-force and credential-stuffing attacks before any business logic runs (ADR-006):- IP-keyed on public routes: 5 req / 300 s on login and register, 20 req / 300 s on the
/auth/*group - User ID-keyed on protected routes: 5 logouts / 300 s, 3 password changes / 3600 s
- Returns
429 Too Many Requestswith aRetry-Afterheader on limit breach - Fails open on cache errors — a cache outage never blocks legitimate requests
- Degrades to no-op when no cache is configured; enabling requires an explicit code change
- IP-keyed on public routes: 5 req / 300 s on login and register, 20 req / 300 s on the
Fixes
-
🔒 INCR+EXPIRE atomicity gap closed — if
expirethrew after a successfulincr, the counter key persisted with no TTL, causing permanent rate-limit lockout for that identifier. The fix wrapsexpirein a nested try/catch and callscache.del(key)on failure. Both failure paths are covered by unit tests. -
🔒
'unsafe-eval'removed from CSP —script-srcincluded'unsafe-eval'with no code requiring it -
🔒 Session limit enforced post-INSERT — the max-3-sessions-per-user check now runs after the new session is inserted, closing a brief window where a 4th concurrent session could exist
Documentation
- ADR-006: rate limiting design, algorithm choice, configuration, and future considerations
- Security audit: full review of rate limiting middleware plus stop-gap audit of the v1.3.0 wizard UI — 2 findings resolved, 1 false positive documented
- Auth flow diagrams: rate limiting rejection steps added to login and register flows
- STRIDE threat model updated: brute-force gap now marked as mitigated
Test Coverage
- 326 unit tests, 63 integration tests (389 total)
- New unit tests cover INCR+EXPIRE partial-failure paths:
expirefailure triggersdelcleanup; both failing still fails open security-headers.test.tsupdated to assert'unsafe-eval'is absent from CSP
Packages (v1.4.0)
@private-landing/core@private-landing/infrastructure@private-landing/schemas@private-landing/types@private-landing/cloudflare-workers
Intended Use
Private Landing is intended for:
- Education & learning around modern authentication systems
- Reference architecture for Cloudflare Workers
- Bootstrapping custom authentication implementations
- Security review and discussion
It is not a turnkey production authentication service.
Stability
v1.4.0 is fully backward compatible. The rate limiter is off by default (createCacheClient = null) — no behaviour changes without an explicit code change. The CSP tightening and session fix are purely additive hardening with no API surface changes.