Alert when a prekey pool runs low (relay#35) #94

Merged
paulhitt merged 1 commits from feat/alert-on-low-prekey-pool into main 2026-09-04 20:41:54 +00:00
paulhitt commented 2026-09-04 09:48:48 +00:00 (Migrated from gitlab.com)

An empty pool is a silent security downgrade, not an inventory
problem.
X3DH uses a one-time prekey so the first message of a session
has forward secrecy even against a later compromise of the signed
prekey. With the pool drained the handshake still succeeds — it falls
back to the signed prekey — and nothing anywhere says so. Both parties
believe they got what the protocol promises.

The client half already existed: the bundle response reports
opk_remaining and the device tops itself up. What was missing was
anybody NOTICING when that loop fails. A device that stopped running, or
a client with a broken top-up, drains its pool once and then hands out
degraded handshakes for ever, and no log line anywhere marks the moment.

The relay cannot fix this and does not pretend to. Only the
device can mint and upload more, and the warning says so — otherwise
somebody goes looking for a server-side switch that does not exist.

The mark is ten, not one. Warning at zero is warning after the
damage: the pool is already empty and every handshake since has been
degraded. Ten is roughly a day of ordinary contact for an active
account, which is time to act.

Nothing is logged for a healthy pool. A line per bundle fetch would
bury the two that matter under thousands that do not. Low is a notice;
empty is a warning, because handshakes are degrading as it prints.

Counted after the pop, so the number reported is what the next caller
will actually find.

554 relay tests and 26 XCTests green, 8 new. Nothing here touches
either app.

**An empty pool is a silent security downgrade, not an inventory problem.** X3DH uses a one-time prekey so the first message of a session has forward secrecy even against a later compromise of the signed prekey. With the pool drained the handshake still succeeds — it falls back to the signed prekey — and nothing anywhere says so. Both parties believe they got what the protocol promises. The client half already existed: the bundle response reports `opk_remaining` and the device tops itself up. What was missing was anybody NOTICING when that loop fails. A device that stopped running, or a client with a broken top-up, drains its pool once and then hands out degraded handshakes for ever, and no log line anywhere marks the moment. **The relay cannot fix this and does not pretend to.** Only the device can mint and upload more, and the warning says so — otherwise somebody goes looking for a server-side switch that does not exist. The mark is ten, not one. Warning at zero is warning after the damage: the pool is already empty and every handshake since has been degraded. Ten is roughly a day of ordinary contact for an active account, which is time to act. Nothing is logged for a healthy pool. A line per bundle fetch would bury the two that matter under thousands that do not. Low is a notice; empty is a warning, because handshakes are degrading as it prints. Counted after the pop, so the number reported is what the next caller will actually find. 554 relay tests and 26 XCTests green, 8 new. Nothing here touches either app.
paulhitt commented 2026-09-04 09:48:48 +00:00 (Migrated from gitlab.com)

assigned to @paulhitt

assigned to @paulhitt
paulhitt commented 2026-09-04 20:41:54 +00:00 (Migrated from gitlab.com)

mentioned in commit 3351daf86d

mentioned in commit 3351daf86dfbc5570ad5ce63756dff0d0f6cba52
paulhitt (Migrated from gitlab.com) merged commit 3351daf86d into main 2026-09-04 20:41:55 +00:00
paulhitt commented 2026-09-09 18:59:14 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
Sign in to join this conversation.