Skip to content

v0.5.1b0 — Epic A: state security (signing, locked fields, CSRF audit)

Pre-release
Pre-release

Choose a tag to compare

@fsecada01 fsecada01 released this 01 Jul 21:36
· 11 commits to master since this 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, versioned cfs1.<payload>.<mac> tokens) + CorruptStateError. Enable via StateSigner.configure(secret) or STATE_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. See docs/STATE_SIGNING.md.
  • Locked server-trusted state fields (A3, #37) — locked_fields: ClassVar[frozenset[str]] for state keys the client must never influence. Excluded from dehydrate(), stripped on hydrate() with a warning; enforced in the core lifecycle so all adapters are covered. See docs/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