This release is mostly a security hardening pass across the whole app — auth flows, uploads, rate limiting, link previews, SSO, SQL input handling, and dependencies.
There's a new Single Transferable Vote (STV) poll type (beta — feedback welcome on GitHub)
We also added support for Cloudflare Turnstile challenge on sign-in, sign-up, and trial creation.
New
- STV (Single Transferable Vote) poll type — beta. Anonymous by default, results hidden until the poll closes. The form shows a warning asking users to report bugs and feedback on
GitHub. - Cloudflare Turnstile challenge on password sign-in, login-token requests, signup, and trial creation. Admin login-link sign-in bypasses the challenge; sign-in with a login code also
bypasses it. - Profile pictures via OAuth (OIDC defaults) on the OAuth client.
- Track email bounces separately from complaints.
- API v2b: new list endpoints for discussions and polls; limit/offset as the primary pagination params (per/from kept as aliases).
- Rails Pulse added for request monitoring (Blazer removed).
Security
- Hardened OAuth/SAML authentication flows; added Google and Nextcloud OAuth controller tests; trust SSO providers fully on auto-link.
- Fixed SQL injection in HasTimeframe via timeframe_for.
- Blocked SSRF in the link preview service; link previews now require auth and are throttled to 20/hour per user.
- Fixed operator precedence in the Group create ability.
- Restricted sensitive fields in serializers.
- Fixed trial email enumeration.
- Direct upload size limit (25 MB trial, 1 GB paid); blocked dangerous uploads.
- Stopped leaking errors in API responses; removed debug logging of secret tokens and emails from the hocuspocus controller.
- X-Robots-Tag: noindex header for non-public instances.
- Bumped vue-i18n to 9.14.5 (XSS + prototype pollution).
- Added Brakeman + bundler-audit to CI.
- Sent rate-limit events to Sentry (grouped by rule+IP to cut noise).
- Safelisted private-network IPs in rack_attack.
- Split the profile GET throttle (tight on email_status, looser elsewhere).
- Gave /bug_tunnel its own throttle and skipped Sentry alerts for it.
Fixes
- Refresh a user's groups after joining or being added to a group.
- Fix translator-mangled i18n interpolation vars + a CI check to catch regressions.
- Handle legacy ImageMagick-style variation keys and Vips::Error in the ActiveStorage variation translator.
- Return a token error on session failure when a login token is pending; translate sessions errors server-side; surface server errors on login code entry.
- Guard Events::PollExpired and real_participant fallback against nil / non-participant eventables.
- Fix demo poll cloning (missing opening_at/opened_at).
- Translation fixes: needs_a_rethink_meaning, "vote in" → "vote on", German typo in discard.
Internal
- Ruby 4.0.2; Puma 8; Vite 8; Vue Router 5; many dep bumps.
- Switched to Minitest/fixtures for group export and OAuth controller tests.