Repository navigation
v0.5.1b0 — Epic A: state security (signing, locked fields, CSRF audit)
Pre-release
Pre-release
Interim beta release shipping Epic A — State Security & Integrity (#21) complete. v0.6.0b0 remains reserved for the full Hardening Foundation milestone once Epic B (DOM morphing) lands.
Added
- HMAC-signed client state (A1, #35) — stdlib-only
core/signing.py:StateSigner(HMAC-SHA256, versionedcfs1.<payload>.<mac>tokens) +CorruptStateError. Enable viaStateSigner.configure(secret)orSTATE_SIGNING_KEY; comma-separated keys enable rotation (first signs, all verify). Enabled: all outbound state signed, tampered/unsigned/raw-dict inbound rejected with 400. Disabled: legacy behavior + one-time warning. Seedocs/STATE_SIGNING.md. - Locked server-trusted state fields (A3, #37) —
locked_fields: ClassVar[frozenset[str]]for state keys the client must never influence. Excluded fromdehydrate(), stripped onhydrate()with a warning; enforced in the core lifecycle so all adapters are covered. Seedocs/LOCKED_FIELDS.md.
Security
- Closed the dict bypass: all adapters route inbound state through
StateSerializer.load_untrusted()— state can no longer be submitted as a raw JSON object to skip verification. - Replay/rollback gap closed: stale-but-validly-signed state can no longer roll back server-owned fields.
- Django
ComponentView.handle_error()maps client input errors (ValueError, incl. corrupt state) to 400 instead of 500.
Documentation
docs/SECURITY_CSRF.md(A4, #36) — per-adapter CSRF coverage table (Django-only today), the form-encoded no-preflight CSRF vector, and CSWSH guidance for all WebSocket adapters.docs/STATE_SIGNING.md(A2) — per-adapter key setup + rotation procedure.
Full test suite: 477 passed across Python 3.11–3.14 (36 new signing tests, 21 new locked-fields tests, zero regressions).
🤖 Generated with Claude Code