Private Landing v1.5.0
🔭 Observability Plugin & Operational Surface
This release introduces a removable observability plugin with structured security event capture, adaptive proof-of-work challenges, an agent-authenticated /ops API for incident response, and a Go TUI for exercising it — all without modifying the core authentication services.
What's New
-
📡 Structured Event Capture
Security-relevant actions (login, logout, password change, rate-limit rejection, challenge escalation, agent auth failure) are persisted to asecurity_eventtable with actor attribution and fire-and-forget semantics — event emission never blocks authentication (ADR-008) -
⚡ Adaptive Proof-of-Work Challenges
The login endpoint escalates SHA-256 PoW difficulty after repeated failures from the same IP (3+ failures → difficulty 3, 6+ → difficulty 5). Complements rate limiting by raising per-request cost without CAPTCHA infrastructure. Fails open on DB error. -
🤖 Agent Identity &
/opsAPI
Non-human agents authenticate with 256-bit API keys (SHA-256 hashed, not PBKDF2 — high-entropy keys don't need stretching). Trust levels (read/write) enforce least privilege. Provisioning is gated by a separate infrastructure secret. All/ops/*routes cloak behind 404 when the provisioning secret is absent. -
🖥️
plctlCLI
Go TUI (Bubble Tea) for interactive session, event, and agent management via the/opsAPI. Zero runtime dependency on the Node/Bun toolchain. -
🪞 Mirrored Session Service
createMirroredSessionServicedecorator ensures SQL visibility for/ops/sessionswhen cache is the authoritative session store — best-effort SQL mirror never blocks auth (ADR-007) -
🔌 Fully Removable
Deletepackages/observabilityand comment the two[obs-plugin]lines inapp.tsto restore the core auth system. CI verifies the core build and tests pass with the plugin removed.
Fixes
- 🔒
timingSafeEquallength leak closed (OBS-4) — both inputs padded to max length before HMAC comparison, eliminating a timing side-channel that leaked the byte-length of the compared secret - 🔒 CLI path traversal (OBS-1) — agent name now escaped with
url.PathEscapebefore URL concatenation - 🔒 CLI query injection (OBS-2) — string concatenation replaced with
net/url.Valuesfor query parameters - 🔒
SELECT *removed (OBS-3) —/ops/eventsuses an explicit column list to avoid auto-exposing future sensitive columns plctlenter key on empty events — no longer panics when pressing enter with no event selected
Documentation
- ADR-007: session dual-write decision record
- ADR-008: adaptive challenges, operational surface, agent identity, CLI tooling
- Security audit (Feb 28, 2026): OBS-1 through OBS-4 findings and remediations
- STRIDE threat model: observability plugin attack surface added (entries 19–27); repudiation gap (#9) marked mitigated; brute-force residual risk (#13) updated for adaptive challenges
- 90-day event pruning command documented in ADR-008
- Stale
app.tsline references corrected in threat model and flow diagrams
Test Coverage
- 426 unit tests, 63 integration tests (489 total)
- Observability plugin: middleware, router, adaptive flow, config, schema, event processing, agent key auth
- Mirrored session service: dual-write, consistency, limit enforcement
plctl: API client, input handling
Packages (v1.5.0)
@private-landing/core@private-landing/infrastructure@private-landing/observability(new)@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.5.0 is fully backward compatible. The observability plugin ships enabled but is removable — commenting the two [obs-plugin] lines in app.ts disables it. The timingSafeEqual fix is a correctness improvement with no API surface change. All existing tests continue to pass with or without the plugin.