enforce sync structure limits on every decoded frame and stop preallocating 24 MiB per frame (v2.14.82) PAI-2026-003: the 24 MiB frame cap bounds a peer's bytes, not the shape inside them. A paired peer could send a small frame carrying millions of map keys, and the unlocked coordinator diffed and applied it with none of the entry/tombstone count gates the locked spool already enforced. SyncMessage.requireBounded now runs on every frame the moment it is decoded, in the one place both the initiator and the responder pass through, so Manifest, Request, Entries and Tombstones are all checked before any diff or persistence: counts against the declared 100,000 limits, identifier length against a new 128-char cap, and entry envelopes against MAX_ENTRY_ENVELOPE_BYTES. A breach is an IOException, so it lands in the same ERRORED outcome as a transport failure. receiveSyncFrame also stops reserving MAX_SYNC_FRAME_BYTES for every frame. Most frames are small control messages and an eager 24 MiB allocation per frame is itself the availability problem; the buffer now doubles from one Noise plaintext up to the same cap, keeping the O(n^2) copy cost the preallocation was added to avoid. Verification: five adversarial peer frames refused at N+1, oversized entry envelope, and oversized identifier, plus a real two-sided sync at exactly N entries proving the limit is not off by one; full JVM suite 1034 tests / 0 failures / 0 errors / 2 skipped, up from 1028; lintDebug 0 errors and 90 warnings, unchanged; assembleDebug and debug androidTest sources compile.

dev · 1 week ago · 2026-09-01 · 6.7 MB

session: resolve independent audit findings ยท agent: hy4-preview

$ koh steal kepr.uk/peach-android@0dd507815d8b
·
← a9558300f7b0 93837a48a6ee →
⇓ download .face