Skip to content

fix: zero-value totp, invisible password characters, non-canonical email local parts, and unpinned controls #478

Description

@Jaro-c

The remaining findings of the 2026-09-25 review of auth/password, auth/totp, auth/email and auth/username. None is a bypass; two change what is accepted.

  1. A zero-value TOTP hashes recovery codes under an empty key, which anyone can compute, and VerifyRecoveryCode on it compares against such hashes. New now requires the secret (fix: harden the password, totp, email and username constructors and fix the otpauth label #475), but the zero value still works. This is the apikey, jwt, field: zero value modules produce output under an empty HMAC key #400/field, credential: public constructors accept a provider with no key material #403 shape the other modules refuse.
  2. Code points that render as nothing satisfy the password policy. U+2800 BRAILLE PATTERN BLANK is a symbol to unicode.IsPrint and counts as the special character; the Hangul fillers (U+3164, U+115F, U+FFA0), U+034F and the other default-ignorable letters and marks pass too. The package claims to refuse "control and invisible characters". A user who registers with one of them cannot see what they typed, which is the lockout A control character satisfies the special character rule #347 describes.
  3. The email local part has several canonical forms, and two mailboxes can share one. normalize lowercases the local part as typed with no Unicode normalisation, so josé@ (NFC) and josé@ (NFD) come back different; U+0130 lowercases to i, so İnfo@ and info@ come back the same (the CVE-2019-19844 shape); and U+200B, U+00AD, U+202E, U+0085 and U+2028 travel into the stored value.
  4. Seven password controls could be deleted with the suite green: NFC in Hash (a user registering with a decomposed password could never sign in), three of the four *bool snapshots fix(password): reject malformed PHC strings and snapshot the policy #437 added, the Memory and Iterations ceilings at New, and the label= prefix check in the PHC parser, without which a stored hash with a bare label makes Verify panic.
  5. The MX cache's eviction and its empty-answer branch could be deleted with the suite green. The eviction test called evictExpired, which nothing in production calls; the eviction that matters lives in store, and a comment still describes a background goroutine that refactor: API ergonomics & consistency (no goroutine, uniform constructors, docs) #135 removed.
  6. Two fuzz targets prove less than they say. FuzzVerify in totp discards both results, so a stepMatches that accepts every code passed 3.3 million executions; the username target does not check the [a-z0-9_-] set it calls the homoglyph control.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions