Skip to content

v1.27.16

Choose a tag to compare

@github-actions github-actions released this 16 Aug 07:53
· 84 commits to main since this release

[1.27.16] — 2026-08-16

Release notes

Security fixes

  • Auth degrades closed, never open. A poisoned token-store lock was an
    empty set → "auth disabled" → allow-all; it is now fail-closed
    500 auth_store_unavailable. A configured-but-empty token store (file or
    env set, zero tokens) denied everything; it now returns 401 instead of
    reading as "no auth". The JWT revocation check (v1.2.0) skipped itself on
    ANY pool/SQL error (if let Ok(conn) + unwrap_or(false)); any store
    failure now denies. The role-retrieval gate (v1.23.0) degraded to "no
    narrowing" (read everything) on a pool/role-store error; it now degrades to
    the empty permit (read nothing) with a warn!. /auth/logout is no longer
    a public route: the presented access token is verified by the middleware
    first — an unauthenticated "logout" could only ever succeed at revoking
    nothing.
  • The multi-db domain registry is now registered-only and capped. In
    BRAIN_MULTI_DB=true, pool_for NEVER opens a file for an unregistered
    name (previously any probeable read created brain-<name>.db lazily —
    unbounded disk fill). POST /domains is the one creation path, bounded by
    BRAIN_MAX_DOMAIN_DBS (default 256; 507 insufficient_storage beyond it);
    every resolution read of an unknown name returns the probe-blind 404
    domain_unknown (indistinguishable from an empty-but-real domain). The
    clients-register boot seed keeps client domains resolvable if their file
    vanished between boots (recreated on first access, still cap-bounded).
  • JWT principals are domain-scoped on reads. /search now authorizes
    against the domain it actually queries (was always global). /get/{id}
    and /multi-get bind the header's X-Brain-Domain label in SQL — an id
    can never cross domains in shim mode — re-authorize on the row's own
    domain, and run the same record gate (v1.14 scopes + v1.23 roles) recall
    enforces; foreign rows read as 404 / are dropped, never loud. Recall
    federation and graph traversal drop foreign-domain targets before any
    search runs; shim-mode graph edges scope by their chunk's provenance label
    (an unlinked edge is invisible to scoped readers).
  • Trust labels are closed vocabularies at the write boundary. /ingest
    rejects an unknown/mixed-case memory_kind (400 invalid_memory_kind
    no silent fallback to fact) and a confidence outside 0.0..=1.0 (400
    invalid_confidence — no silent clamping, a clamped lie hides the liar);
    the proposal path (/proposals) enforces the same strict kind round-trip.
    A JWT (agent) principal on /add may only use the closed source
    vocabulary (ingest kinds + connector family kinds) — manual, the
    origin:human marker, is excluded so a token-authenticated agent cannot
    forge human authorship. The UMP L3 operator signing key now fails closed to
    L2 on a group/world-readable seed file (same 0600 enforcement the other
    secrets get).
  • The per-IP rate limiter actually was not per-IP. The serve wiring never
    injected the peer SocketAddr extension, so every client shared ONE
    "unknown" bucket — a global rate limit in practice. The server now serves
    with into_make_service_with_connect_info, buckets are keyed by remote
    address (production-behavior pinned by a source-inspection test), and the
    bounded key set (RATE_LIMIT_MAX_KEYS) evicts the oldest 25% rather than
    growing unbounded.

Improvements

None.

Bug fixes

None.

Full Changelog: v1.27.15...v1.27.16