What's Changed
Highlights
TeamPass 3.1.7.0 is a major feature release introducing real-time WebSocket synchronization, a complete overhaul of the permissions engine, significant performance improvements, and a wide range of security hardening and bug fixes accumulated across five release candidates.
New Features
Real-Time WebSocket Synchronization
A new WebSocket server (Ratchet 0.4.4 + ReactPHP) provides live updates across all connected clients without page refresh.
- Item events — create, update, delete, and move operations are broadcast instantly to all users viewing the same folder.
- Edition locking — when a user opens an item for editing, all other users see a live lock indicator. The lock is released automatically on disconnect, save, or cancel.
- Folder events — folder create, rename, delete, and permission changes are pushed in real time.
- User & task events — encryption key readiness (
user_keys_ready), background task progress, session expiry, and system maintenance notifications. - Role permission refresh — when an administrator changes role permissions, all affected users receive a folder-tree refresh immediately without re-login.
- Auto-reconnect — the JS client reconnects with exponential backoff (max 30 s, 10 attempts) and a secure reconnect token (never passed in URLs).
- Systemd unit (
teampass-websocket.service) included for production deployments. - WebSocket can be enabled/disabled from the admin panel; host/port are configurable via
teampass_misc.
Permissions Engine Overhaul
- Direct folder grants restored — folders assigned directly to a user (via
users_groups) always grant full write access, regardless of any role-level restriction on the same folder. - Least-permissive multi-role resolution — when a user holds multiple roles that disagree on a folder's access level, the most restrictive permission wins (write > no-delete > no-export > read).
- Effective permission helper (
evaluateFolderAccesLevel()) introduced inmain.functions.phpand used consistently across items and users. - Deprecated
list_folders_limitedandlist_restricted_folders_for_itemssession variables removed; all checks now use the unifieduser-accessible_folders. - Per-user direct grants now passed as the base allowed set to
identUserGetPFList(), restoring correct folder visibility after a role change.
Folder Rights Panel Redesign (Users page)
- Folder rights now displayed in a scrollable modal instead of an inline card.
- Animated progress bar while folder data loads.
- Client-side filter buttons for permission types (W / ND / NE / R / no access).
- "Roles" column showing one badge per contributing role and its individual permission type.
Roles & Folders Page Improvements
- Folder list loads faster with continuous (non-blocking) rendering.
- Forms replaced by modals for a cleaner UX.
Options Management
API Enhancements
- New endpoint
GET /api/item/allTags— returns all tags across items accessible to the authenticated user. - Browser extension: accessible folders now resolved from
cache_treeinstead of the JWT payload, preventing stale folder lists after permission changes.
Browser Extension — Dashboard Status
- Admin dashboard now displays the browser extension licence status.
Performance Improvements
APCu Configuration Cache
ConfigManager caches the full teampass_misc settings table in APCu shared memory (60 s TTL, key teampass_settings_v1). Cache is invalidated automatically after any write via ConfigManager::invalidateCache(), eliminating redundant DB reads on every request.
Optional Redis Session Storage
SessionManager supports Redis-backed sessions via RedisSessionHandler wrapped by EncryptedSessionProxy. Falls back to filesystem on connection failure. Configurable via redis_host, redis_port, redis_prefix, and redis_session_enabled in teampass_misc. gc_maxlifetime is now set dynamically to prevent premature PHP garbage collection.
Batch Sharekey Upserts
storeUsersShareKey() now executes a single batched INSERT … ON DUPLICATE KEY UPDATE (chunked at 100 rows) instead of N individual queries, reducing DB round-trips from O(users) to O(1) per item save.
cache_tree Optimizations
- N+1 SQL queries in
tree.phpreplaced with in-memory lookups (pre-loaded$completTree), reducing ~400–600 queries to 1 for a 200-folder tree. - Per-user cache invalidation via a new
invalidated_atcolumn — only users with access to the affected folder have their cache marked stale. Global invalidation (last_folder_change) removed. - Visible folders are now built synchronously in the same rebuild pass; a separate async background task is no longer needed.
- Missing
idx_user_idindex added tocache_tree.user_id.
WebSocket Poll Interval
EventBroadcaster poll interval reduced from 200 ms to 500 ms to lower contention on teampass_websocket_events under high load.
Items Page
- Unnecessary AJAX calls removed during item edition.
- Item list refresh triggered immediately on add/delete.
- Faster item save (background encryption task launched immediately).
- Improved multi-item edition with immediate lock release.
Security
SQL Injection Fixes (API)
- In
ItemController(getAction,inFoldersAction,findByUrlAction): JWT folder/item IDs now sanitised witharray_map(intval, ...). - User-supplied label/description passed through
DB::escape()instead of raw string interpolation. - Internal exceptions logged server-side; only a generic message returned to the client.
- N+1 sharekey queries in
findByUrlAction()replaced with a singleIN()query.
WebSocket Security Hardening
- Single-use tokens:
validateFromToken()now enforcesused = 0and marks the token used atomically on success; token validity reduced from 3600 s to 60 s. - Reconnect token: a long-lived reconnect token is generated after successful initial auth and transmitted only over the WS channel (never in a URL); the JS client uses it for all subsequent reconnection attempts.
- Object injection prevention:
@unserializereplaced withallowed_classesrestriction. - Per-user API permissions: WS token holders now receive permissions from
teampass_users.api_allowed_to_*columns instead of unconditional full CRUD access. - IP-based rate limiting for failed auth attempts (max 10 failures / 60 s per IP), applied before any credential validation.
- Double-delivery prevention: EventBroadcaster poll+mark cycle wrapped in a DB transaction with
SELECT FOR UPDATE. - Expired
websocket_tokenspurged in the existing hourly cleanup timer.
XSS Prevention
- Sanitisation added on two newly exposed fields to prevent XSS.
- Guard added in
main.functions.phpwhen the master encryption key is empty.
HTTP Security Headers (API)
X-Content-Type-Options, X-Frame-Options, and Referrer-Policy headers added to all API responses.
AES Private Key Migration
xss_clean() removed from AES private key derivation path (it was corrupting binary-safe key material); transparent migration added for existing keys.
Bug Fixes
| Issue | Description |
|---|---|
| #5104 | OAuth2 / Azure Entra — three bugs fixed: FK violation on new user creation, missing name/email in DB and missing confirmation email, "login credentials do not correspond" error on second login |
| #5108 | Items list showed wrong access rights after a role was deleted because restriction_to_roles was not cleaned up; restriction_to_roles is now purged on role deletion and an INNER JOIN is used in the rights query
|
| #5111 | mfa_auth_requested_roles was not re-computed after LDAP checks, causing MFA to be skipped in some configurations
|
| #3956 | AD group-to-role mapping broken: binary objectGUID is now normalised to a formatted string so it matches getADGroups() output; ldap_groups_roles deduplicated and UNIQUE KEY added on ldap_group_id
|
| #5114 | Miscellaneous fixes (see commit 8e8df67)
|
| #5124 | Missing SQL instruction in fresh install process |
| #5103 | Fallback crash when preg_split() returns false
|
| #5106 | Admin page fix |
| #5102 | Several bugs identified and fixed in the items view |
| #5065 | Items page improvements and fixes |
| #5131 | Implemented and improved (see commit cf05e9ec)
|
| #5132 | Applied provided fix |
| — | 2FA method selector was shown to all users regardless of whether their role required MFA; now only displayed when relevant |
| — | Notification bug when notifications are enabled for an item |
| — | When another user updates an item currently being browsed, the UI now refreshes automatically |
| — | Session-error modals now displayed when server returns ERROR NOT ALLOWED, ERROR SESSION EXPIRED, or the forced-disconnection message
|
| — | Fix WebSocket start/stop control in admin panel when the daemon is managed by systemd |
| — | Docker installer: DB connection over TCP fixed; Docker documentation updated |
| — | MySQL ONLY_FULL_GROUP_BY compatibility fixed across all SQL queries
|
| — | Manager access correctly restricted to System Health and specific user views |
| — | Files Integrity Check: warning block added for folders that cannot be parsed due to permission errors |
| — | Admin Dashboard: direct shortlink added to System Health card |
| — | Item moved events now broadcast via WebSocket; edition lock correctly shown in item detail panel |
| — | Edition lock enforced on item delete and move operations |
| — | Permissions: create right, role restrictions, and item form fixes applied
|
Upgrade Notes
Database Schema Changes (upgrade_run_3.1.7.php)
- New tables:
teampass_websocket_events,teampass_websocket_tokens,teampass_websocket_connections. - New table:
teampass_cache_treeimprovements (invalidated_atcolumn,idx_user_idindex). - New table:
teampass_favorites. roles_valuestable: orphans and duplicates purged,UNIQUE KEYadded.ldap_groups_roles: deduplicated, corruptedINT(12)entries purged,UNIQUE KEYonldap_group_id.- New
teampass_miscsettings:redis_session_enabled,redis_host,redis_port,redis_prefix,websocket_enabled,websocket_host,websocket_port. - AGSES column renamed.
PHP Extensions
The installer and upgrade wizard now check for (optional) extensions: OPcache, APCu, ext-redis, PHP-FPM. None are mandatory, but APCu and Redis are recommended for production performance.
Composer
firebase/php-jwtupgraded from v6.9 to v7.0.- All other Composer dependencies updated.
WebSocket Daemon (optional)
If you want real-time synchronisation, start the WebSocket daemon:
php /path/to/teampass/websocket/bin/server.php
# or use the provided systemd unit:
systemctl enable --now teampass-websocketThe daemon requires ext-pcntl and ext-posix (CLI only). Configure websocket_enabled = 1 in Admin > Settings.
Code Quality
- PHPStan analysis raised to level 4 (previously level 1); errors fixed across
sources/,api/, and custom classes. - PHPUnit setup added with initial test suite covering authentication flows and the
Encryptionclass. Encryption::decrypt()null guard added.scan_corrupted_items.phpdiagnostic script added underscripts/.
Removed / Deprecated
list_folders_limitedandlist_restricted_folders_for_itemssession variables removed.- Deprecated direct folder restriction mechanisms removed from the permission engine.
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.