v0.4.0 — security-hardening audit pass
A full security-hardening pass from an audit of the library. go build, go vet, gofmt, and go test ./... (incl. -race) pass.
TwoFactorStore gains ClaimTOTPStep(userID uint, step uint64) (bool, error) — an atomic TOTP replay guard. Both reference stores are updated; custom implementations must add it.
Security
- Fail closed on a weak/absent
SESSION_SECRET— signing refuses a key <32 bytes (an unset secret previously signed cookies with an empty, publicly known HMAC key); HS256 pinned viaWithValidMethods. - Account-linking invariant enforced on the primary OIDC callback — rejects an unverified email like the social path; both stores require the incoming login to prove the email before rebinding a verified/bootstrap row; gormstore squatter-reclaim is now atomic.
- Sign in with Apple no longer blocked by CSRF —
/auth/social/*/callback(Appleform_post) is CSRF-exempt (guarded by the OAuthstate). - 2FA brute-force throttling — limiters install with a
TwoFactorStore;/auth/reauthand/auth/2fa/disableare rate-limited. - Atomic TOTP replay guard (
ClaimTOTPStep) + monotonic WebAuthn sign counts; disabled-user checks on 2FA completion. AssumeVerifiedonly fills an absentemail_verified; recovery codes widened to 80 bits.- Request body-size limits (incl. SCIM
/Bulk) + SCIM filter depth cap; open-redirect backslash fix. - SCIM —
activedefaults true, strongIf-Match, non-leaking errors, duplicate-group 409, PATCH group replace/valuePath-remove. - LDAP — paged search, honor
InsecureTLSforldaps://, DN normalization. - Email/SMTP — HTML-escaped URLs, CRLF header sanitization, magic/reset sends off the request path (anti-enumeration timing).
Added
Config.BrandName/BRAND_NAME— email + WebAuthn RP branding (replaces the hardcoded app name).- Transparent bcrypt rehash-on-login.
Authenticator.Close()stops the built-in rate-limiter GC goroutine.
Full details in CHANGELOG.md.