Priority: low — hardening, not an active incident. Found during the 2026-06-11 operational-flow audit (F3).
The member-facing flow (OrdersController, CreditItemsController, EmailPreferencesController, MenusController via UserHashidable) authenticates by a ?uid= hashid that identifies the user and skips authenticate_user!. These links are emailed to members. The security of every per-user action therefore rests on the hashid being unguessable, which depends on HASHID_SALT.
Hardening steps:
Context: the token is currently unscoped (one uid authorizes order read/write + email prefs + credit purchase) and never expires.
Priority: low — hardening, not an active incident. Found during the 2026-06-11 operational-flow audit (F3).
The member-facing flow (
OrdersController,CreditItemsController,EmailPreferencesController,MenusControllerviaUserHashidable) authenticates by a?uid=hashid that identifies the user and skipsauthenticate_user!. These links are emailed to members. The security of every per-user action therefore rests on the hashid being unguessable, which depends onHASHID_SALT.Hardening steps:
HASHID_SALTis set to a strong, random secret on Heroku (and is not committed). If unset, hashids fall back to a predictable default.config.sign_hashidsinconfig/initializers/hashid.rb.message_verifier) rather than a permanent token that authorizes orders, credit purchases, and preference changes all at once. Consider requiring a real session for credit purchases and order edits.Context: the token is currently unscoped (one
uidauthorizes order read/write + email prefs + credit purchase) and never expires.