v0.15 Security Review
v0.15 Security Review
Status: v0.15.0 release evidence. This record describes source review and regression coverage, not an independent security certification.
Implemented Hardening
| Boundary | Change | Regression evidence |
|---|---|---|
| Aggregate resource use | Wire transactions have a 64 MiB aggregate body limit, including per-operation body separators. BGET has a 64 MiB encoded response limit. LISTR and RETRIEVE bound retained payload bytes to 64 MiB. | Small-limit exact-boundary and over-limit tests against a persistent server; rejected transactions have no committed intent or partial records. |
| Client response memory | LISTR, RETRIEVE, and RINGS account for cumulative payload/vector bytes before reading further bodies. BGET continues to enforce encoded body bounds. | Fake peers advertise aggregate overflow or malformed bodies; the client rejects the response and opens a fresh connection for the next request. |
| Header integrity | Authentication and galaxy tokens reject control characters and whitespace; each token is at most 2 KiB. sendFrame rejects newline, carriage return, NUL, and oversized headers. | Input matrix and C ABI contract. Binary payload bodies are unaffected. |
| Connection ownership | Failed connection setup closes its socket, including authentication, TLS, and galaxy handshake failure paths. | Repeated rejected authentication checks open-descriptor counts on Linux. Existing TLS contracts exercise setup. |
| Ambiguous mutations | Automatic transport retry is limited to explicit read-only and protocol-idempotent control allowlists. An ordinary mutation whose send/ack path fails raises IndeterminateWriteError rather than being sent again. | A fake peer consumes PUTR and drops its acknowledgement; only one write request arrives. A failed read and a fenced coordinator control each make at most two attempts. |
| Codec state | Read reconnects repeat negotiated codec metadata setup; close clears the negotiation cache. | A dropped LISTR response followed by reconnect and explicit close still returns the BIF codec. |
The public Nim API exposes this exception as KoutenIndeterminateWriteError.
For public C ABI calls, unknown write outcomes use the existing error return and
last-error channel. This change does not add a new ABI status code or provide
exactly-once delivery. Applications must reconcile an unknown write outcome
instead of blindly retrying it. Replication workers retain their explicit,
version-aware retry queues; the generic RPC transport no longer silently
replays ordinary mutations. Cluster commits and mirrors with stable transaction
identities, fenced coordinator operations, and deduplicated Universe events
remain retryable because their protocol identities make exact replay safe.
Oversized operations fail explicitly rather than returning silently truncated results. Reduce list limits or retrieve budgets, narrow rings, or split batches. Splitting a transaction changes its atomicity boundary and must be an explicit application choice. These are per-request bounds, not a total process-memory quota; vector dimensions, row counts, concurrent clients, and storage metadata also contribute to memory consumption.
Passwords sent inside the encrypted challenge response are not whitespace- delimited header fields and retain their existing content support. Ordinary AUTH passwords and tokens must fit the header-token contract.
Validation
The new matrix is available as:
bash scripts/wire_security_matrix.sh
It is included in the full smoke entry point and the Linux smoke CI job.
The extended C ABI contract also runs in the existing macOS job.
Its server uses a 4 KiB test-only aggregate limit so boundary coverage
does not require large allocations. Production builds retain 64 MiB limits.
Linux-only descriptor counting is skipped where /proc/self/fd is unavailable;
the protocol tests remain portable.
On 2026-09-25, local Linux validation passed the new matrix, core/store tests, ring/role authorization, TLS, wire fuzz cases, driver wire contracts, cluster transactions, C ABI TLS/boundary contracts, and the Clang ASan/UBSan contract with leak detection enabled. The new matrix contains four Nim test cases and thirteen Python integration cases, including parameterized malformed-response and input-boundary checks. No sanitizer diagnostics were emitted.
The release acceptance workflow requires the configured Linux and macOS jobs to pass on the release commit. Configuring a CI job is not itself evidence that it ran. Another endurance run was not part of this focused review.
Transport Policy And Slow Clients
Non-loopback authenticated listeners now require TLS unless the operator uses
the explicit development-only --allow-insecure-auth escape hatch. The
SECRET_KEY challenge and encrypted-frame layer remains available as an
additional gate, but is not accepted as a substitute for verified TLS.
Header and body reads now use cumulative deadlines. A peer that sends one byte before every socket timeout can no longer retain the single request loop indefinitely. The security matrix includes a slow-drip regression that verifies another authenticated client becomes responsive after the bounded deadline.
Release Acceptance
Publish v0.15.0 only after the release commit passes remote CI and the final diff contains no generated binaries, local paths, or credentials.
No claim of absence of all vulnerabilities follows from these tests. See the threat model and security validation matrix for deployment boundaries.