Skip to content

Remote peers can force expensive synchronous PBKDF2 via ocap-URL redemption #1036

Description

@sirtimid

A remote peer can force the kernel to run expensive synchronous key derivation by sending redeemURL messages, at a cost that blocks the event loop.

Mechanism

#handleRedeemURLRequest (packages/ocap-kernel/src/remotes/kernel/RemoteHandle.ts:879-889) handles an inbound redeemURL message and passes the peer-supplied string straight to redeemLocalOcapURL (remotes/kernel/remote-comms.ts:339-356), which calls cipher.decrypt.

The cipher is AES_GCM.create() with no options (remote-comms.ts:240), so @libp2p/crypto's password-mode defaults apply: pbkdf2Sync(key, salt, 32767, 16, 'sha256') per operation, synchronous. The salt is read from the ciphertext, so nothing can be cached across calls, and the cost is paid before authentication fails — garbage oids cost exactly as much as valid ones.

Measured

per operation:        4.39 ms
throughput, 1 core:    228 ops/sec

The default per-peer message rate limit is 100/s (remotes/platform/constants.ts:20), so one peer can demand roughly 0.44 CPU-seconds per wall second — about three peers saturate a core. Because pbkdf2Sync is synchronous, the impact is not just throughput: the kernel's event loop stalls in 4.4 ms chunks, so unrelated kernel work pays the latency.

Why this is filed separately from #777

The underlying construction is #777's to review, and the proper fix — not stretching an already-uniform 256-bit key — is a change to the URL format, which needs a version prefix and a transition window (see #777 for both). But this is exploitable today, whether or not that review happens, and mitigations do not depend on it:

  • reject structurally invalid oids before the expensive step (length, base58 validity) — helps against unstructured garbage;
  • bound concurrent or queued redeemURL work per peer, independently of the general message rate limit;
  • move the derivation off the main thread so a stall costs throughput rather than whole-kernel latency.

Filed so the exposure is tracked on its own terms rather than waiting on a review whose timeline is unknown.

Related: #777 (the construction and the real fix), #989 (key custody; same code path, different concern).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingocap-bug-fixOCAP Kernel bug fix

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions