Skip to content

3.2.1.7

Latest

Choose a tag to compare

@nilsteampassnet nilsteampassnet released this 18 Aug 10:02
5e53dba

What's Changed

This release brings customizable email templates to the 3.2.1 line, adds a Health page for reading the server logs from TeamPass itself, and continues the client-side XSS hardening started in 3.2.1.6. It also refreshes the Docker base image and every Composer dependency, clearing the vast majority of the vulnerability alerts reported against the published image. Upgrading is recommended for all installations.

This release changes the database schema. UPGRADE_MIN_DATE is raised, so every installation goes through the upgrade wizard once, which creates the new emails_templates table.

🔒 Security fixes

  • The upgrade wizard now really enforces its administrator check (issue #5329, reported by @alvarez86) - step 0 destroyed the session before storing the upgrade grant, so the check had no server-side effect at all; the wizard only worked because upgrade.php re-created the grant from a POSTed hidden field, and a misplaced parenthesis made steps 1, 2, 4, 5 and 6 skip the check whenever the step came from the form. The session identifier is now regenerated instead of destroyed, the grant stays server-side only and is required on every step. The administrator password is no longer written to the session, it was never read back from there.

  • Link secrets no longer appear in the Health page log excerpts - access logs record the full request line, and TeamPass carries link secrets in the query string (Secure Send links, attachment and backup download keys). Every runtime log excerpt now masks secret values before display.

  • The client-side purifier is split into an inbound and an outbound entry point - simplePurifier() served two unrelated purposes: rejecting markup in what the user typed, and cleaning what the server returned before rendering it. The two contracts do not follow the same rules, which is what let nine XSS reports land on screens whose authors assumed a purified value was safe to concatenate. It is now four functions with explicit contracts, and the ten direct call sites were routed to the one matching their direction. The LDAP and OAuth2 new-role list boxes, which built their options from directory group names without encoding, are encoded as well.

  • Status and error messages rendered as markup are now encoded - the sweep also covers four sinks that the encoding sentinel could not see because it only matched a single-level path, three of them rendering the name of a file the user picked for upload. The sentinel now matches any dotted path before the watched field.

  • The WebDAV backup client no longer follows redirects - its requests carry Basic credentials towards an administrator-supplied URL, so a redirect must never be able to replay them towards another host. This can stop an externalized WebDAV destination that used to work, see the upgrade note below for how to identify and fix it.

  • The shared confirmation dialog is hardened - dialog labels are emitted with json_encode() instead of addslashes(), backup file names inserted in the message are encoded, and the action click no longer propagates to delegated handlers left by other flows. A sentinel test covers both rules. The email-template reset now goes through the same shared modal (PR #5335, @guerricv).

  • Vendored crypto-js updated to 4.2.0 - fixes CVE-2023-46233 (weak PBKDF2 defaults below 4.2.0: SHA-1 and a single iteration), reported as critical by the image scan. TeamPass was not actually exposed, as its wrapper always passes hasher, keySize and iterations explicitly, so the defaults were never used. For the same reason the update cannot break existing data.

✨ New features

  • Customizable email templates - every email TeamPass sends can now have its subject and its body rewritten by an administrator, per language, from a new page under Configuration. Emails are grouped by domain, with a language selector, a rich text editor and a preview rendered with sample values. The storage is a pure diff over the shipped language files: an empty table keeps the current behaviour byte for byte, and reverting a template is simply deleting its row. A body that lost a required placeholder is refused, #password#, #reset_url#, #enc_code# and #2FACode# are what make the email usable. The setting emails_templates_enabled acts as a global kill switch, and both actions are logged as admin_action.

  • Health page: server log reading (PR #5323, PR #5334, @guerricv) - new cards on the Utilities page surface the WebSocket logs and the server access log directly in TeamPass, with the merged rotation files and the scope of the selected log reported alongside. A read that exhausts its budget is reported as truncated rather than silently empty.

🛠️ Improvements

  • Docker base image moved to Alpine 3.24 - Alpine 3.19 had reached end of life, so its OS packages no longer received security updates and the CVEs reported against them could not be fixed while the image stayed pinned there: around 42 of the 48 open code-scanning alerts came from that base image. PHP stays on 8.3 and only the Alpine version moves; musl, OpenSSL, curl, SQLite and BusyBox all move well past their fixed versions. The dead LD_PRELOAD of preloadable_libiconv.so, shipped by no Alpine package and only making every process log an ld.so error, is dropped.

  • All Composer dependencies updated within their existing constraints - this clears the five Dependabot advisories on guzzlehttp/guzzle (1 high, 4 medium), which was pulled in transitively through league/oauth2-client. The Composer builder stage moves to the current 2.10 line.

  • Development dependencies are no longer part of an installation - PHPUnit, PHPStan and its precompiled native extensions, the license checker and their transitive packages are never loaded at runtime, so on a server they were dead weight and needless attack surface. Both the installer and the upgrade now remove them, so a fresh install and an upgraded one end up with the same tree.

  • Email subjects are customizable end to end - the prefixes some emails carried (TEAMPASS - , [Teampass] ) were concatenated at send time whatever the administrator had saved. The prefix is now part of the shipped default only, so the editor loads the complete line and the preview prepends nothing.

  • mail_me no longer accepts a subject and a body from the browser - it takes a catalog identifier and resolves the text server-side.

  • The notification dropdown is bounded and themed (PR #5332, @guerricv, for issue #5331) - the menu no longer grows past the viewport, and its scrollbar follows the active theme.

  • Every published security advisory is listed in the security policy, and the advisory form is named as the only supported reporting channel.

  • CodeQL no longer analyses vendored third-party code, which was drowning the real findings.

🐛 Bug fixes

  • The upgrade wizard no longer freezes on its spinner (issue #5329, reported by @alvarez86) - the wizard opened its alertify spinner with a 0 timeout and parsed every answer with an unguarded $.parseJSON() inside the complete callback. A PHP fatal, a 500 page or any stray output made the parse throw, so both spinner-dismissal branches were skipped and the page looked frozen with no message. The calls are now guarded, .fail() handlers report the HTTP status and the raw server answer, and the server buffers its answer so output emitted before the JSON no longer corrupts it. The step 5 report, base64-encoded JSON parsed without a guard, was a second instance of the same freeze.

  • Managers no longer lose their session when opening the recycled bin (issue #5325, reported by @reginfo) - the recycled bin and logs pages are granted to managers, but the knowledge base maintenance actions in kb.queries.php enforced an administrator-only restriction at page level. The page-level check is kept while the administrator-only restriction stays enforced where it belongs.

  • The site URL confirmed in the upgrade wizard is now saved (discussion #5308, @issonia-ma) - the wizard asked for the full URL to TeamPass but never stored it, so an instance moved to another path during the upgrade kept the old value. The confirmed URL is persisted at step 2, before the version scripts run, together with the favicon and the files folder URL.

  • Item deletion modal fixes (PR #5333, @guerricv) - the delete button stays enabled after a deletion request, deletion goes through the shared showItemDeleteModal(), and the modal state is reset when it is hidden.

  • The item creation email no longer contains the literal string email_body3 - a language key that exists nowhere was appended inside the message.

  • Classification history entry and long URL display fixed.

  • Email templates keep their formatting when saved - prepareExchangedData() purifies by default and purifyData() returns plain text for every field not named description, so a saved template lost its markup. The colour and alignment buttons are dropped as well: both emit inline styles, which the sanitizing applied when the email is sent removes anyway.

  • The encryption key and world-writable checks in the permissions documentation are corrected (discussion #5276, @Sky-W-ui).

⬆️ Upgrade notes

  • Schema. The upgrade creates the emails_templates table and seeds emails_templates_enabled to 1. UPGRADE_MIN_DATE is raised, so every installation goes through the wizard once.

  • Email templates start empty, and an empty table means today's behaviour. Nothing changes for your emails until an administrator saves a template; reverting one is deleting its row. Set emails_templates_enabled to 0 to fall back to the shipped strings without losing the templates.

  • Email subject prefixes moved into the shipped defaults. If you script or filter on the TEAMPASS - / [Teampass] prefixes, note that they are now part of the editable default line rather than being concatenated at send time.

  • WebDAV backup destinations must now point at the final URL, not at one that redirects. Redirect following is disabled on the externalized WebDAV client, for the connection test as well as for the transfers. A server that answers with a 30x no longer works silently: the connection test reports WEBDAV_CONNECTION_FAILED and the write test WEBDAV_NOT_WRITABLE. The usual causes are an http:// URL redirected to https://, a host name the server canonicalises (example.com to www.example.com), or a collection path rewritten to its canonical form with a trailing slash.

    To find out, send a PROPFIND to the exact URL configured in the externalized backup destination (bck_externalized_webdav_url):

    curl -sS -o /dev/null -w '%{http_code} %{redirect_url}\n' \
      -u 'user:password' -X PROPFIND -H 'Depth: 0' \
      'https://your-server/your/remote/path/'

    A 207 means the URL is already the right one. A 301 or 302 prints its target next to the status: copy that value into the destination URL and run the connection test again. Nothing else changes, the credentials, the remote path and the schedule stay as they are.

  • The development dependencies are removed from app/vendor on upgrade. If you run the TeamPass test suite from a production checkout, reinstall them with composer install.

  • Docker users: the image now builds on Alpine 3.24. Rebuild or pull the new image to pick up the OS security updates.

  • Back up your database before upgrading, as always.

Full Changelog: 3.2.1.6...3.2.1.7

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