What's Changed
Security fixes
- WebSocket token replay prevention — tokens are now single-use; a long-lived reconnect token is issued over the WebSocket channel only after successful authentication, eliminating URL-based token reuse.
- IP-based rate limiting on failed authentication — the WebSocket server now blocks IPs that exceed 10 failed auth attempts within 60 seconds, before any credential is validated.
- SQL injection hardening in the API — folder/item IDs from JWT payloads are now sanitized with
array_map(intval) in getAction(), inFoldersAction(), and findByUrlAction(); user-supplied strings go through DB::escape(). - Object injection prevention — unserialize() calls in AuthValidator now restrict allowed classes.
- Correct API permissions for WebSocket users — api_allowed_to_* columns are now read from the database instead of granting full CRUD to every WebSocket token holder.
- Double-delivery prevention — the EventBroadcaster poll cycle is wrapped in a SELECT FOR UPDATE transaction to prevent duplicate event dispatch when multiple daemon instances run concurrently.
- Security headers — X-Content-Type-Options, X-Frame-Options, and Referrer-Policy headers added to all API responses.
New features
- Real-time item move notifications — when an item is moved (single or mass move), all users subscribed to the source and destination folders receive an item_moved event immediately. The item row is removed from the source folder view and the destination folder list is refreshed automatically.
- Edition lock badge in the item detail panel — when another user opens an item for editing, the lock indicator now appears directly in the detail/read panel, not only in the folder list. The badge is removed automatically when the lock is released.
Bug fixes
- MySQL ONLY_FULL_GROUP_BY compatibility — fixed a GROUP BY violation in the sharekeys backup query in tools.php (non-aggregated columns created_at, user_id, login added to the clause).
- Edition lock race condition — lock badges are now re-applied to item rows after an AJAX list reload, preventing cases where a lock received via WebSocket before the DOM was ready would be silently lost.
- Drag-and-drop move guard — moving an item via drag-and-drop is now blocked when that item's detail panel is currently open, preventing inconsistent UI state.
Developer / infrastructure
- PHPStan level 4 compliance across all modified files.
- websocket/src added to PHPUnit coverage scope; pcov enabled in phpunit.xml.
- New unit tests and stubs for WebSocket components (ConnectionManagerTest, WebSocketFunctionsTest, MockWsConnection).
- /coverage/ added to .gitignore; .phpunit.result.cache removed from version control.
Full Changelog
Important
- Requires at least
PHP 8.1
Languages
Please join Teampass v3 translation project on Poeditor and translate it for your language.
Installation
Follow instructions from Documentation.
Upgrade
Follow instructions from Documentation.
Ideas and comments
Are welcome ... please use Discussions.