github nilsteampassnet/TeamPass 3.2.3.0

5 hours ago

What's Changed

This release brings passkeys to TeamPass, in two independent features. TeamPass can now keep the passkeys of third-party sites in its items, like it keeps their passwords, and the browser extension signs in with them. Users can also sign in to TeamPass itself with a passkey, as a second factor or without a password. Both are off by default. Beyond passkeys, Secure Send gains an activity journal and usage statistics, the administrator dashboard shows failed sign-ins in its live activity, the Folders and Roles pages stay usable on trees of several thousand folders, and the Profile page is reorganised in sections. The release also fixes signing out in Safari, the upgrade from 2.x stopping after the key file is renamed, and the file integrity scan staying in progress on NFS storage. It closes a High severity authorization flaw in the administration of roles by managers (GHSA-j3ph-4847-695h): upgrading is recommended for every installation, and required for those that give the Manager or HR manager privilege.

This release changes the database schema. UPGRADE_MIN_DATE is raised, so every installation goes through the upgrade wizard once: it adds four tables and eight settings, and empties one column that nothing read. The structure of the existing tables is unchanged.

πŸ”’ Security fixes

  • Managers are bound to their own roles and folders on the Roles page (GHSA-j3ph-4847-695h, High) - the Roles page is open to managers and HR managers, who administer the roles they hold or created, on the folders they can access. The server did not enforce that scope: a manager could read and change the folder rights of any role, including giving their own role read and write access to every shared folder, and rename, re-flag or delete any role. Where roles are mapped to AD groups, a manager could also map any group to any role, a setting the interface only offers to administrators. Every handler now checks the role against the roles the caller may grant, and the folders against the ones the caller can access, personal and denied folders excluded. A request naming one folder outside that scope is refused as a whole, propagation never leaves it, the AD group mapping is reserved to administrators, and the role list of the page shows the same scope. Affected: 3.0.0.0 to 3.2.2.8. The matrix part of the fix came with PR #5427 (@guerricv).

✨ New features

  • Passkeys of other sites, kept in TeamPass - when a site offers to create a passkey, the browser extension saves it in a TeamPass item, and signs in with it when the site asks for it later. The private key never leaves the TeamPass server: it is generated there (ECDSA P-256, ES256), encrypted like an item password with one sharekey per user, and used there; the extension only relays the request of the site and receives a signature. Everyone who can open the item can use its passkeys, so a passkey saved in a shared folder signs in for every member of that folder, and one in a personal folder for its owner only; folder rights, item restrictions and the recycle bin apply as they do to passwords. Every use is written to the item history (Passkey added, Passkey deleted, Passkey used, with the site), the item logs can be filtered on Passkey used, and the user who saves a passkey can receive a customizable email naming the site, the account and the item. The item card lists the passkeys of the item and lets whoever can edit it delete one, and a fingerprint next to the title marks the items that hold one. Passkeys follow their item when it is moved, are never copied or exported, and are covered by Restore missing sharekeys. TeamPass's own sign-in passkey is never kept in an item: the server refuses it and the extension leaves it to the browser, since an item holding it would let everyone who can open it sign in as its owner. Enable it in Settings β†’ API β†’ Browser Extension (Allow the browser extension to save passkeys); each user can still turn it off in the extension settings. The extension uses four new API endpoints, webauthn/create, webauthn/list, webauthn/assert and webauthn/delete, under the user's API rights: Read to sign in, Update (and the right to edit the item) to save or delete. Requires the browser extension 1.8.0 or later. See Passkeys.

  • Sign in to TeamPass with a passkey - a fingerprint, a face, a PIN or a security key can now confirm a TeamPass sign-in instead of a code, or replace the password entirely. Users register their passkeys from Profile β†’ Sign-in and security β†’ Sign-in passkeys (up to 20, renamed or deleted from the same list), after confirming their password β€” an open session alone cannot add a passkey; an administrator or a manager of the account revokes them from Users β†’ action menu β†’ Sign-in passkeys. Nothing is imposed: unlike Google Authenticator or Duo, turning the feature on asks nothing of the accounts that have no passkey, there is no enrolment during sign-in, and where another method is already required, the passkey is offered next to it. In passwordless mode, a local account signs in with its passkey alone: the passkey then carries an encrypted copy of the user's encryption key, opened either by a secret only the authenticator can produce (PRF) or, for the authenticators without PRF, by a key derived from the instance secret file β€” a setting refuses the latter, and turning it on deletes the copies already registered, after a confirmation that gives their number. Directory (LDAP) and OAuth2 accounts keep their passkey as a second factor, since a sign-in without the directory password would bypass a directory that may have disabled the account. Regenerating a user's encryption keys deletes the copies their passkeys hold. Additions, deletions and passwordless changes are logged, a refused passkey counts towards the account lockout like a wrong password, and the owner is emailed when a passkey is added. The login page prepares the passkey request before the click, so a single click opens the browser dialog; a passkey left without a name takes the name of the passkey manager that holds it (Windows Hello, Google Password Manager, Apple Passwords…); the profile says when a passkey is not asked for because MFA is unchecked on the account, and when the only passkey stays on a single device; a passkey deleted in TeamPass is reported to the browsers that implement the WebAuthn Signal API, so that the device stops offering it; and Monitoring β†’ Logs tells a sign-in made with a passkey alone from a password one, and names the passkey. Administrators follow the adoption at a glance: a badge in Users gives the number of sign-in passkeys of each account, in orange when they are not asked for, and the Active Users tile of the administration dashboard counts the accounts that hold one. While passkeys are the only multi-factor method enabled, the dashboard recommendations say so instead of reporting that no method is enabled: an account without a passkey still signs in with its password alone. Configure it in Settings β†’ MFA β†’ Passkeys (Disabled, As a second factor, Passwordless and as a second factor). HTTPS is required: browsers only offer passkeys in a secure context. See Signing in to TeamPass with a passkey.

  • Secure Send activity journal (PR #5417, @guerricv) - every Secure Send link now leaves a durable trace in a dedicated journal: creation, successful reveal, wrong key or passphrase, revocation by its sender, invalidation (sender or item no longer available, too many failed attempts, item automatically deleted) and expiry cleanup. The journal holds metadata only β€” the sender, the source item id, the protection policy and the counters β€” never the shared content, a label, the link or its passphrase, and it survives the deletion of the link, the item or the account. Each event is written in the same transaction as the operation it records: if it cannot be written, the operation fails without returning a link or a secret. When syslog is enabled, events are also forwarded as action=secure_send after commit. The journal starts at the upgrade (no past event is rebuilt) and keeps every event unless an administrator sets a retention (see below). One behaviour changes: a link whose source item's automatic deletion has already elapsed is now removed when it is opened, instead of being kept. See Secure Send β€” Audit scope.

  • Secure Send usage in the statistics (PRs #5418 and #5419, @guerricv) - Statistics β†’ Users gains a Secure Send usage card fed by the activity journal. Over the selected period it gives the links created, the successful reveals, the failed credential attempts and the number of senders who created links, a breakdown by event (revoked, invalidated, expired), by type (item, note), by protection (with or without a passphrase) and by access (public, internal), and the five senders who created the most links, with their reveals and failed attempts. Disabled and deleted accounts, and accounts that no longer exist, stay in the ranking with a label. Only the period filter applies: the Personal and API toggles do not, because the journal does not record where an item came from. The card keeps showing the recorded history when Secure Send is disabled, and reports the activity as unavailable rather than zero when the journal cannot be read (the cause is written to the server log). Counters start at the upgrade, like the journal. A reveal means that the server decrypted the content, not that an identified recipient read it, and failed attempts on a sender's links do not prove an abuse by that sender: nothing is blocked automatically. See Secure Send β€” Usage statistics.

  • Retention of the Secure Send activity journal (PR #5425, @guerricv) - the journal keeps every event by default. Settings β†’ Collaborative & advanced features β†’ Secure sharing gains Secure Send audit retention (days): 0 keeps everything, a value from 1 to 36500 deletes the events older than that number of days. Saving the setting deletes nothing by itself: the purge is done by the Items integrity scan maintenance task, so only when that task is scheduled in Tasks, and each run removes at most 1000 events, the oldest first β€” a large backlog drains over several runs. Each batch is deleted in the same transaction as a summary written to Utilities β†’ Logs β†’ Administration under the TeamPass system account (retention, cutoff date, number of events deleted), and the summary is forwarded to syslog when it is enabled. A purge that cannot run writes its cause to the server log and deletes nothing. Deletion is permanent, and the Secure Send usage card only counts the events still in the journal: a period older than the retention shows less than what happened. Backups and external log collectors keep their own copies. See Secure Send β€” Audit retention.

  • Failed sign-ins and a larger view in the administrator live activity (PR #5415, @guerricv) - the Live activity tile of the administration dashboard only showed item and knowledge base events, so nothing told an administrator that users were failing to sign in. A gear menu now selects what the tile shows: item changes, item consultations, failed sign-ins and lockouts, successful sign-ins, and knowledge base activity. Item events and the knowledge base stay selected by default, so the tile looks as before until an administrator opts in; the choice is kept per administrator, in the browser. A failed sign-in shows the login that was typed, even unknown or misspelled, and the recorded reason, and a counter gives the failures of the period whatever the number of rows displayed. An expanded view lists the last 5, 15 or 30 minutes, 50 events at a time, with the Web or API channel of each sign-in, and refreshes by itself while it is at the top of the list. The feed reads the existing journals: it changes neither the authentication, nor the lockout rules, nor what is logged, and adds no table or setting. See Administrator live activity.

πŸ› οΈ Improvements

  • The Folders page stays usable on large trees (PR #5426, @guerricv) - with several thousand folders, Folders was slow to open and to use: the server read the path of each folder one by one, and the browser built the whole table and the complete parent lists. Paths now come from a single snapshot of the tree. Above 100 folders, branches start collapsed, 100 rows are displayed at a time (Show more folders adds the next 100), and the search, which covers names and parent paths, also finds the folders of collapsed branches. Selections survive filtering and collapsing, and selecting a parent includes its descendants that are not displayed: the counter and the deletion confirmation count them. The parent of a folder is chosen in a list that searches on demand, 30 results at a time. See Folders.

  • The Roles permission matrix stays usable on large trees (PR #5427, @guerricv) - the same approach applies to Roles: the tree and the rights of the role are loaded in bulk instead of folder by folder, branches start collapsed above 100 folders, 100 rows are displayed at a time, and the search matches names and full paths, special characters included. Selection and expansion are kept for the rows that are not displayed, the comparison with another role also applies to the rows displayed later, and a late answer for a role no longer replaces the one selected since. See Roles.

  • Folders and Roles show the same folder tree (PR #5428, @guerricv) - both pages now use the same chevron to open a branch, a button in the header that expands or collapses the whole tree, the same folder icons and the same muted parent path.

  • The Profile page is organised in six sections - the Information, Settings and Timeline tabs give way to a menu: Overview, Sign-in and security, Browser extension, Preferences, Activity and Help and advanced. A section that has nothing to show for the account is left out of the menu. Local accounts see their password block with a shortcut to the change-password panel, the extension section says whether the extension is set up in the current browser, and the buttons of the passkey, token and API connection lists are named. The page script no longer stops at the API key button when the API is disabled. Links to ?tab=settings and ?tab=timeline keep working. See Profile.

  • The current password sent with a password change is no longer stored - the password-change handler copied the current password field of the request, as received, into the users.last_pw column, and the sign-in loaded it into the session, although nothing read it. No TeamPass screen sends that field, so the column is empty on a normal installation: a value could only come from a request crafted by a user about their own password. The handler no longer writes it, the session no longer holds it, and the upgrade empties the column, including the hash lists TeamPass 2.x kept there.

  • Items created or deleted through the API appear in the author's open folder - item events sent by the API excluded their author, a rule copied from the web pages, where the author's page refreshes itself. An API client is never that page, so an item created or deleted through the API, or a passkey saved by the extension, stayed invisible in the folder the author had open until the page was reloaded.

  • One notification for an item created then updated at once - when a client creates an item and changes it immediately, as the browser extension does when it attaches a passkey, the folder showed new item followed by item updated. An update within 15 seconds of an announced creation now refreshes the list without a second notification.

πŸ› Bug fixes

  • Signing out and opening the profile work again in Safari (issue #5429, reported by @michaldejmek) - on the Items page, clicking Log out or My profile in the account menu did nothing in Safari. These entries are # links whose click handler did not cancel the link itself: the browser followed it right after the redirect was requested, the back-button guard of the Items page reacted, and WebKit cancelled the redirect. The handler now cancels the link, and so does the one of the sidebar entries, which are built the same way.

  • The upgrade from 2.x no longer stops with an HTTP 500 after renaming the key file (#5423) - the migration procedure names the legacy teampass-seckey.txt in settings.php. The wizard renames it to a random name and rewrites settings.php, but the rest of that request kept reading the old name and failed with BadFormatException while generating the administrator keys. Relaunching the upgrade got past it. The wizard now runs that step again by itself right after the rename. The rewrite also stops double-encoding non-ASCII characters in settings.php.

  • The file integrity scan no longer stays in progress on NFS storage (#5416, PR #5420, @guerricv) - to tell whether a scan is running, the Health page tries to lock the scan lock file, which it opens read-only. On NFS, such as Longhorn RWX volumes under Kubernetes, an exclusive lock needs a file opened for writing: the attempt always failed and was read as a running scan, so the page showed Scan in progress forever and kept the button disabled until the lock file was deleted by hand. The check now takes a shared lock, which stays read-only and still detects a running scan. A lock that cannot be checked at all is reported with its own message instead of a running scan, and the results of the last scan stay visible.

  • The permission repair plan covers the data folders stored on their own volume (PR #5422, @guerricv) - the plan printed by file_integrity.php --permissions-plan merged the runtime folders under their parent and ran find -xdev, which does not cross mount points: the content of a runtime folder mounted separately was left unrepaired. It also changed the ownership recursively, beyond what its mode commands covered. Every runtime folder is now an explicit starting point, ownership and modes use the same selection, and the paths that go through a symbolic link are listed for a manual review instead of being followed. On a new installation, the installer now writes the encryption key file readable by its owner only (0600). See File permissions.

  • Accented and special characters on the Renewal page (PR #5430, @guerricv) - an item named ArrivΓ©e was displayed as Arrivée, and folder names had the same problem: names are stored with HTML entities, and the page escaped them a second time. Labels and folder paths are now decoded before they are displayed, and the search and the sorting use the text that is shown: typing amp or quot no longer matches every encoded name, and accents are still ignored.

  • A new password is no longer refused because of a very short name - a new password may not contain the login, the name or the lastname of its owner, and the rule applied whatever their length: a user called Li, or whose lastname is a single letter, was refused every password holding those letters, with a message about the complexity level. Words of one or two characters are now ignored, and the refusal states the whole rule.

  • The statistics tables no longer keep loading after a failed refresh (PR #5419, @guerricv) - when the Statistics page could not load its data, an error was shown but the roles, users, items and endpoints tables kept their spinner. They now say that the data could not be loaded.

πŸ“š Documentation

  • New Passkeys page, covering both features: enabling, API rights, who can use a passkey, audit, item lifecycle, security model, what a passwordless passkey holds, restrictions, revocation and troubleshooting. The authentication, profile, users, email templates, settings and browser extension pages point to it.
  • The items guide names the sharing link feature Secure Send instead of One Time View, and keeps the old anchor so existing links still work.
  • New Administrator live activity page.
  • File permissions is rewritten around the repair plans the command line prints, instead of a whole-tree ownership command: temporary write access for the wizard and normal runtime are separated, the two ways of protecting the key file are explained (owned by root with the PHP group, or owned by the PHP account), and a manual repair script is given for the other Linux distributions. The installation, upgrade and hardening guides follow.
  • The Docker guides give the real location of the encrypted attachments, storage/upload/, and every backup example now lists the five volumes of the image.
  • The Folders and Roles guides describe how large trees are browsed, and the Profile guide follows the new sections.

⬆️ Upgrade notes

  • The upgrade wizard runs once (UPGRADE_MIN_DATE raised). It creates webauthn_credentials (the passkeys of other sites), sharekeys_webauthn (their per-user keys), user_webauthn_credentials (the sign-in passkeys) and secure_send_audit (the Secure Send activity journal), and adds eight settings: webauthn_provider_enabled (0), webauthn_email_on_add (1), webauthn_login_mode (0), webauthn_login_require_prf (0), webauthn_passwordless_satisfies_mfa (1), webauthn_rp_id (empty: the host of the TeamPass URL), webauthn_rp_name (TeamPass) and secure_send_audit_retention_days (0: every Secure Send journal event is kept). Both passkey features stay off until an administrator enables them. It also empties users.last_pw, a column nothing read; the structure of the existing tables is unchanged.
  • Serve TeamPass over HTTPS before enabling passkeys. Sign-in passkeys do not work over plain HTTP. For the passkeys of other sites, also enable Require HTTPS for API requests: whoever intercepts the extension's session can ask TeamPass to sign in to third-party sites. Monitoring β†’ System Health warns when passkeys are enabled while the API still accepts plain HTTP.
  • Changing the relying party ID makes every registered sign-in passkey unusable: authenticators bind a passkey to that domain. Choose it before users register theirs. TeamPass refuses a value that is neither the host of the TeamPass URL nor one of its parent domains, and asks for a confirmation when passkeys exist.
  • Passwordless sign-in counts as MFA by default: a passkey can then replace an imposed Google Authenticator or Duo factor. Turn Passwordless sign-in counts as MFA off to keep them mandatory.
  • A passkey kept in TeamPass needs the TeamPass server. Its private key never leaves the server: while the server is down or unreachable it cannot be used, and it is not part of the offline HTML export. Keep another way to sign in β€” a password, recovery codes β€” on every account it protects.
  • Restoring a backup loses the passkeys saved since that backup: the sites still expect them. Back up after saving passkeys.
  • Review what managers did on the Roles page. A manager or HR manager now only sees and administers the roles they hold or created, and no longer maps AD groups to roles. TeamPass did not log these changes: check the permission matrix of each role and the AD group mappings for entries nobody set. The advisory gives a query that lists the rights left on personal or deleted folders.
  • A folder can no longer be created in, or moved to, a parent that is read-only for the user. The parent lists already did not offer those folders; the server now refuses them too. Administrators are not concerned.
  • The key file of an existing installation keeps its permissions. Only a new installation writes it 0600. To review an existing one, print the plan with php app/scripts/file_integrity.php --permissions-plan, run as the PHP account, and apply the commands you have checked.
  • New production dependency: web-auth/webauthn-lib (MIT licence), which verifies passkey registrations and sign-ins.
  • Back up your database before upgrading, as always.

Full Changelog: 3.2.2.8...3.2.3.0

Important

  • Requires at least PHP 8.2

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.

Download TeamPass

Don't miss a new TeamPass release

NewReleases is sending notifications on new releases.