Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

#209

P1: Bound sign-in names, passkey labels, and rate-limit keys

closed · opened by keenan 2d ago

keenan opened this 2d ago

Why

Several values in the browser sign-in flow are stored before they are bounded:

  • LoginBegin takes the account name from the request, builds the per-account rate-limit key as "login:"+name, and stores the name in the ceremony. The name is not checked against identity.ValidateName (2–32 characters) before either use. The rate limiter keeps keys until its 65,536-key cap and does not sweep expired entries before that, so the length of the key is chosen by the client. An unauthenticated request can grow the tables by the size of the name it sends.
  • AddPasskeyBegin stores the request’s label in the ceremony and then in user_credentials. validateCredential bounds the credential id, public key and AAGUID, but not the label, transports, or attachment. An authenticated account can add records whose size it chooses.
  • clientAddress returns the configured forwarding header as-is, so an oversized header can become a rate-limit key when a proxy header is configured.

The ceremony map has a 4,096-entry cap and a five-minute TTL; the rate limiter has a 65,536-key cap. Both cap the number of entries, not the size of one.

Scope

  • Validate and bound the account name before it reaches beginAccount or a ceremony; use a fixed decoy name for invalid input so the response does not become a format oracle.
  • Bound the passkey label and the remaining credential metadata in validateCredential and at the begin handler, so the value is refused before the ceremony or the database stores it.
  • Bound or normalise clientAddress — accept an IP or a short host token, and cap the key length in rateLimiter.allow as a backstop.
  • Sweep expired rate-limit entries as the table grows, not only at the cap, or state why the current behaviour is safe with bounded keys.
  • Add tests for an oversized name, an oversized label, and an oversized forwarding header: each is refused or truncated, and the limiter map does not grow with input length.

Acceptance

  • A request cannot make the rate-limit or ceremony tables grow in proportion to a client-supplied string.
  • An invalid name still gets the same decoy response as an unknown account.
  • Passkey labels and credential metadata are bounded in one place, refused before storage, and covered by tests.
  • Any operator-visible limit is described in docs/operations.md.

From the internal review for #106.

Comments (0)

No comments yet.