Skip to content

Release history

Tuwunel releases

High-performance and feature-rich chat server for Matrix, and the successor to conduwuit (fork of Conduit).

All releases

7 shown

Config change
v1.7.0 Breaking risk
Crypto / TLS Auth Breaking upgrade

Cache changes + MSC features + bugfixes

v1.6.2 Mixed
Notable features
  • Policy server support via `enable_policy_servers` and `policy_server_request_timeout` config keys (MSC4284)
  • Account locking and suspension features with admin mass-reject command (MSC3939, MSC4323, MSC3823)
  • Implementation of Olm fallback key re‑issuance on claim (MSC2732)
Full changelog

Tuwunel 1.6.2

May 8, 2026

We have started a specification compliance campaign which will continue over the next several releases until synced with 1.18 (or 1.19 if it takes that long). Current status will be kept up to date in our documentation.

New Features & Enhancements

  • Policy server support (MSC4284) ships; two new config keys: enable_policy_servers and policy_server_request_timeout.

  • Account locking and suspension (MSC3939, MSC4323, and MSC3823), plus an admin command to mass-reject pending invites.

  • MSC2732 Olm fallback keys are implemented and re-issued on each subsequent claim, so clients keep receiving after key exhaustion.

  • MSC4380 invite blocking (partial).

  • MSC4406 sender_ignored on single-event endpoints.

  • MSC4383 /versions discovery.

  • MSC4260 user reports.

  • MSC4373 incoming-EDU types over federation.

  • MSC4168 m.space.* state copied on upgrade.

  • MSC4169 backwards-compatible redactions on send.

  • MSC3905 local-only users namespace matching for appservices.

  • MSC4025 partial erase on /deactivate.

  • MSC3391 account-data deletion.

  • MSC4361 non-federating member auth rules.

  • MSC4190 appservices now skip UIA on cross-signing key replacement.

  • MSC4254 OIDC revoke handler is tightened across request shape, error codes, and provider lookup.

  • MSC4175 Timezone-key routes have been updated to the stabilized form.

  • Thanks to @DBendit who opened (#316): a complete list of MSCs Tuwunel supports is now in the docs.

  • @dasha-uwu shipped cleanups: appservice file filter, conditional admin lookup, two-member room naming, thumbnail logging, remote media ids.

Bug Fixes

  • Sliding-sync bump_stamp is graciously fixed by @lhjt in (#449), so Element X and other clients move rooms in the sidebar on new activity.

  • Thanks to @humemm for (#448), where OAuth responses returning expires_at as a Unix timestamp tripped login; the upstream DTO is now decoupled.

  • Tip of the hat to @maxrdz for the NGINX root-domain delegation example in (#446), with default port and a resilient $backend indirection.

  • State resolution corrections: knock auth v7-9 (aea509fe5), auth-difference (631c51aa8), mainline 0 (82132eec4), v12 bootstrap-join (aaa6a1a55). A few were upstreamed to Ruma.

  • A long-standing /sync concurrency heisenbug (b1ac65b60), originally introduced in Conduit and made slightly worse by optimizations which took place in v1.3.0, has finally been zapped.

v1.6.1 Breaking risk
⚠ Upgrade required
  • Config key `sso_aware_preferred` renamed to `oidc_aware_preferred`; old name kept as alias
  • Byte‑size config values now accept SI/IEC unit strings (e.g., `64MiB`, `2GB`) in addition to raw integers
Security fixes
  • OIDC `/userinfo` now rejects plain Matrix access tokens, returning WWW-Authenticate: Bearer on 401; token endpoint returns 400/invalid_grant instead of 500 for client errors; PKCE `plain` is disallowed (only S256 allowed); added Cache-Control: no-store to prevent token leakage
Notable features
  • Next-gen OIDC account management with in‑browser session list, end flows and profile page (MSC2965)
  • Appservices receive EDUs scoped to their namespaces (`m.typing`, `m.receipt`)
  • systemd watchdog keep‑alive pings via `WatchdogSec=30`
Full changelog

Tuwunel 1.6.1

May 1, 2026

New Features & Enhancements

  • Next-gen OIDC account management, courtesy of @shaba in (#407), implements MSC2965 and provides the in-browser session list, session-end flows, and profile page for users authenticated via OIDC. The same PR fixes URL-encoding of idp_id in the SSO redirect path and adds the SSO/OIDC bypass path through User-Interactive Authentication so that users without a password can complete UIAA-protected actions. This closes (#433) opened by @jonathanmajh. Thank you!

  • Appservices with receive_ephemeral now receive EDUs scoped to their namespaces in (#406), shipped by @chbgdn and closing (#382). m.typing and m.receipt now route to subscribed bridges and bots. Confirmation testing was provided by @gymnae, thank you both!

  • systemd watchdog keep-alive pings were graciously added by @VlaDexa in (#415). Unit files declare WatchdogSec=30 and the runtime pings systemd, so an unresponsive process is restarted automatically; previously-tolerated long stalls (e.g., pathological state-resolution) may now trigger restarts.

  • Spoofing-resistant client-IP resolution with a configurable ip_source was contributed by @theredspoon as a security finding (#427), implemented and landed across (#428) and (#429). The new ConfiguredIpSource extension and ClientIp extractor replace axum_client_ip::InsecureClientIp across the API, restoring trust in client IPs for rate-limiting and audit logging. Default behavior is unchanged for existing deployments; operators behind a trusted proxy should set ip_source to opt in.

  • MSC3030 (/timestamp_to_event) is implemented (experimental), contributed by @donjuanplatinum in (#413). Clients can now jump to a specific point in time within a room. This is the third Matrix Spec Change @donjuanplatinum has shipped to Tuwunel and we are very grateful for the consistent contributions.

  • MSC3824 (delegated authentication / refresh-token capability) is advertised on /versions and LoginType::Sso includes delegated_oidc_compatibility. The config key sso_aware_preferred is renamed to oidc_aware_preferred, with the old name accepted as alias.

  • Thanks to @rexbron, who contributed extensive operational documentation in (#354) and (#438): a testmatrix example in the troubleshooting section, podman-quadlet examples, an OIDC Keycloak provider example, refactored troubleshooting links, and clarification of how to obtain provider_id for the user admin commands. Thorough work!

  • @valentimarco wrote a complete Authelia authentication page in (#278), closing their own (#274) on the OIDC token endpoint. Thank you!

  • Thanks to @winyadepla for reorganizing the calling chapter in (#431), clarifying TURN vs MatrixRTC and the rationale for Docker-only deployment. This addresses (#348) opened by @MadMan247. Thank you both!

  • Thank you @alametti for adding an Authentik provider section in (#437).

  • Configuration values that name byte sizes now accept SI/IEC unit strings (64MiB, 2GB, etc.) in addition to raw integers.

  • A persistent LRU cache was added for userdevicesessionid_uiaainfo to keep ongoing UIA sessions alive across restarts.

  • Performance: appservice EDU conditions reworked for concurrent lazy serialization; lazy-loading witness write-back gained a mode argument; the legacy spacehierarchy runtime cache was replaced by a database-backed path (config key roomid_spacehierarchy_cache_capacityspacehierarchy_cache_ttl_min/spacehierarchy_cache_ttl_max).

  • Admin: new commands to dump PDUs to the filesystem, query the RocksDB sequence number, and force/override or bypass database migrations.

  • Bootstrap stamps a server_name marker into the global column family (backfilled on first boot for pre-existing databases) so a misconfigured server_name pointed at the wrong database is caught on every start.

  • The media_storage_providers config option now validates that named providers exist; an explicit empty provider list defaults to all configured providers.

  • New documentation chapters: Authentication Systems overview, JWT auth, LDAP auth, multimedia and storage, storage-provider environment variables. Identity-linking semantics for trusted vs. untrusted IdPs are now documented. The development chapter links hosted rustdocs (newly deployed via CI) and a Testing section was added. (#324) opened by @TheButlah on the NixOS Module documentation is closed.

  • OCI image labels now include accurate org.opencontainers.image.version and related metadata derived from the package, closing (#356) opened by @rexbron. Thank you for the detailed write-up!

Bug Fixes

  • OIDC server-contract hardening: /_tuwunel/oidc/userinfo rejects plain Matrix access tokens (with WWW-Authenticate: Bearer on 401); the token endpoint returns 400/invalid_grant instead of 500 on client errors and emits Cache-Control: no-store; PKCE plain is no longer accepted (only S256); the m.oauth UIA flow routes through /login/sso/redirect when no specific IdP is selected.

  • Storage-provider variant naming is now consistent, with appreciation to @yonzilch for (#414). Both sub-tables use lowercase identifiers ([global.storage_provider.<ID>.s3]), unblocking environment-variable configuration. Existing S3 configurations are still accepted.

  • OpenBSD startup is fixed in (#422), tip of the hat to @Hukadan. core_affinity_rs misreports CPU counts on OpenBSD; Tuwunel now uses num_cpus there. Thank you for picking this up!

  • @alaviss reported a 1.6.0 regression in (#432) where inline [global.appservice.<ID>] config no longer worked. Fixed in (9d10230ba); the appservice ID from the toml section is honored again. Sincere apologies for the inconvenience.

  • Multiple users reported the room-spaces hierarchy endpoint returning incomplete or invalid results: @vrisalab in (#344) and @foxing-quietly in (#399). The hierarchy unit was refactored, optimized, and corrected (including discarding m.space.child events with empty content per MSC1772/MSC2946). Special thanks to @TheBrigandier for testing and confirming the fixes on both threads.

  • Thanks to @utop-top, who reported in (#411) that S3 uploads to Cloudflare R2 timed out for large media (~200 MiB+). Multipart uploads now kick in above a configurable multipart_threshold (default 100 MiB). We appreciate the patient testing!

  • Thank you @utop-top for also reporting in (#401) that appservice E2EE was broken because /whoami wasn't returning a device_id per MSC3202, crashing matrix-hookshot on startup. Tuwunel now accepts and asserts the appservice-supplied device_id per MSC4326. Confirmation testing was provided by @Domoel, thanks to you both!

  • @BVollmerhaus reported in (#327) that mautrix bridges (e.g., mautrix-signal) couldn't upload device keys via MSC4190, blocking Element's upcoming mandatory device verification rollout. The MSC4190 path no longer stores as_token as the access token, and honors the appservice-asserted device_id on create. Special thanks to @1matin, @Domoel, and @gymnae for active testing across the thread.

  • Sliding-sync long-polls now release on client disconnect, credit to @chocycat for (#386). Refreshing a client no longer leaves the previous poll holding the connection mutex for the full timeout. Supplemented by task-detach and shutdown-timeout abstractions on main.

  • Thanks to @kodazavr for the immediate report in (#444): Tuwunel failed to start with Sentry integration enabled because the Sentry transport was missing a TLS backend. The reqwest transport is now built with merged webpki roots.

  • Thank you @dennisoderwald for catching in (#443) that OIDC discovery advertised response_mode=fragment while the authorize endpoint only accepted query. Both modes are now implemented through the authorize/complete path.

  • @dennisoderwald also reported in (#434) that S3 storage worked over HTTP but not HTTPS. The missing tls-webpki-roots feature was added to the object_store dependency. Confirmation testing was provided by @ZoftTy and @kodazavr, thank you all!

  • Thanks to @dlford for the report in (#403) that clearing the presence status message had no effect. Now implemented with correct state transitions.

  • Thank you @oly-nittka for the careful diagnosis in (#385) that federation with matrix.org was failing: a stale SRV cache entry overrode the .well-known delegation, producing port 8443 instead of 443. The actual_dest_2/actual_dest_3_2 resolver paths now parse explicit ports from delegated hosts.

  • @native4don reported in (#377) that device_lists.changed was missing from /sync after cross-signing key uploads or device-key changes. The per-room device-key-change row was restored and the sync path updated. Confirmation testing was provided by @rexbron and @x86pup, thank you all!

  • Thanks to @Giwayume for spotting in (#376) that GET /_matrix/client/v3/devices returned null for display_name and was not spec-compliant. The Ruma Device type now skips serializing optional fields when absent.

  • Thank you @foxing-quietly for the report in (#372) that GET /room_keys/version returned 500 instead of 404 for stored backups predating the algorithm field. A backup-algorithm serializer now migrates legacy records on the fly.

  • @kuhnchris reported in (#435) that AppService regex matching was case-inconsistent. User and alias namespaces now use case-insensitive comparisons, matching how MXIDs are normalized. Thank you!

  • @Himura2la updated the LiveKit configuration documentation to the modern form in (#420), addressing (#400) reported by @Morgan-SL-PUP. Thank you both!

  • Thanks to @grinapo for noting in (#317) that the Caddy .well-known example used incorrect CORS syntax. The example was corrected.

  • Thank you @jameskimmel for correcting the Docker port mapping in the example to match the listener (#393).

  • A regression in state_cache where the per-user transit step was wiping the room-wide invite-via cache was fixed in (efd36ddf2).

  • The base_path option for S3 bucket paths was fixed in (85688e5a2) (regression from 73d110727).

  • The UIAA flow for m.oauth and other non-SSO flows was corrected in (de8e2a1f3) so password and other flows still advertise correctly alongside SSO/OIDC.

  • Device last_seen_ip is now updated from the relevant client handlers in (e90272795).

  • The device_list update is now included in /sync for plaintext rooms (0adec1e3a), matching the spec. Operators can revert to 1.6.0 behavior with device_key_update_encrypted_rooms_only=true.

  • @dasha-uwu landed several spec-compliance and cleanup fixes: legacy media endpoints removed (a1bb05e5f), correct error code returned when OIDC is not configured to silence Element Web's warning (dfbab637c), M_UNRECOGNIZED status code changed from 405 to 404 to stop breaking CORS preflight (b926cd939), proper 405 returned for bad methods (e3b2ce6e1), the spurious "skipping presence update" log line removed (287140748), and HTML template fixes (a1742ac3). Thank you, dasha!

Honorable Mentions

  • @theredspoon's client-IP work warrants a second mention: a self-reported issue, a clean two-PR refactor for the fix, and willingness to coordinate the change across every handler in the API crate. This is exactly the kind of contribution every project hopes to receive.

  • @rexbron is now a serial documentation contributor and operations-focused thinker. Between the testmatrix example, the podman-quadlet content, the Keycloak guide, and the OCI image-label report, this release was meaningfully better for it.

  • @donjuanplatinum has now shipped MSC3030, MSC3706, and MSC2246 to Tuwunel across recent releases. Thank you for the steady stream of spec implementations.

v1.6.0 Breaking risk
⚠ Upgrade required
  • Configuration option `allowed_remote_server_names_experimental` is marked experimental; its name will change in a future release without the `_experimental` suffix.
Breaking changes
  • Removed v1 `send_join` and `send_leave` APIs as per MSC4376.
Notable features
  • Next-Gen Auth OIDC server supporting ElementX and SchildiNext (MSC2964/2965/2966/2967)
  • S3 storage backend with configurable media providers and experimental sync migration
  • User‑Interactive Authentication for Next‑gen OIDC (MSC4312) adding cross‑signing/identity reset
Full changelog

Tuwunel 1.6.0

April 9, 2026

New Features & Enhancements

  • Next-Gen Auth OIDC server enhancing ElementX and SchildiNext has arrived! It all began only a month ago with (#342), a large draft PR by @lytedev assessed by the Tuwunel team to be several months away. What happened next was truly extraordinary. Starting with @chbgdn and followed by @siennathesane, @DonPrus and @shaba an entire project within this project assembled to test and iterate this branch at a rapid clip. The OIDC server now builds on existing infrastructure in Tuwunel previously used for SSO. If you have an Identity Provider configured already for use with SSO then the OIDC server Just Works. Huge thanks to everyone involved. (Implements MSC2964/2965/2966/2967)

  • S3 Storage support is now available! Starting from (#362) graciously developed by @exodrifter, Tuwunel now introduces multiple media backends with configurable sections. Support currently includes S3 endpoints and local filesystem directories. The existing media directory is now itself a configurable storage provider implied by the section [global.storage_provider.media.local]. See the examples under [global.storage_provider.<ID>.S3] to configure your own S3 provider. Then list it in media_storage_providers to download media from it, and store_media_on_providers for uploading media to it. Experimental migration support is available with the !admin query storage sync command. SPECIAL UPDATE: Thanks to testing by @utop-top large uploads (~200 MiB) may not work for some S3 providers until additional support is added in 1.6.1. We apologize for this limitation.

  • User-Interactive Authentication for SSO accounts (MSC2454) has been made possible thanks to @chbgdn in (#389). Accounts no longer require setting a password to use features protected by UIAA flows. Users wishing to disable password authentication on their account altogether may do so by changing it to a single asterisk '*' character (use the admin room commands if your client refuses this password change).

  • User-Interactive Authentication for Next-gen OIDC (MSC4312) was implemented by serial auth-system contributor @chbgdn in (#405). This provides cross-signing/identity reset functionality for ElementX and co.

  • Asynchronous media uploads for appservices was implemented thanks to @donjuanplatinum (MSC2246) in (#347).

  • Thanks to @dasha-uwu the appservice_dir can be configured to a directory containing all your appservice yaml files.

  • @donjuanplatinum implemented the server-side for fast-joins (MSC3706) in (#349). Thank you!

  • Thanks to @ventureoo we support sockets managed by systemd after (#360) (issue #355).

  • @vladexa prevented duplicate reactions from being sent by a client to maintain spec compliance with (#353), thank you!

  • Thank you @alametti for adding delegation examples (e.g. example.com to matrix.example.com) to the documentation in (#352).

  • Thanks to @Lama-Thematique the admin room user registration notice was improved in (#387).

  • Thank you @dasha-uwu for implementing the MSC4143 endpoint.

  • Thank you @dasha-uwu for removing the report score per MSC4277.

  • Thank you @dasha-uwu for removing v1 send_join/leave as per MSC4376.

  • RocksDB compaction details are logged for the curious in verbose logging builds.

  • Numerous performance optimizations including JSON deserialization and allocator optimizations.

  • Sliding-sync no longer persists subscriptions across requests.

  • Configuration option allowed_remote_server_names_experimental added as exclusive federation allow-listing. NOTE: the _experimental suffix was added to indicate the logic of this feature will change in an upcoming release and the suffix will be removed. We sincerely regret this inconvenience.

Bug Fixes

  • Thank you @jameskimmel for fixing the nginx configuration for http/2 support. (#391)

  • @exodrifter fixed various errors and typos in documentation (#343), some reported by @RhenCloud in (#338). Thank you both!

  • @vladexa fixed systemd reloading by sending monotonic time after consultation with @rexbron. (#359) Thank you both!

  • Thanks to @exodrifter the media delete range commands now have improved verbiage as of (#375).

  • @yefimg fixed the UIA password flow not being advertised to LDAP users due to regression (#378). Special thanks for this!

  • Thank you @proximalriver for fixing the missing server keyword in the nginx example. (#383)

  • @chbgdn fixed the m.change_password capability not being set based on login_with_password. (#388) Thank you!

  • Thank you @centromere for reporting cross-platform build regressions in #357 which were fixed.

  • Thank you @Ada-lave for reporting a regression with admin startup commands in #320 which we fixed.

  • @0x1af2aec8f957 reported the new systemd-friendly listener system required reuse-address flags to be set (#374). Thank you for reporting!

  • Thank you @Batmaev for reporting non-compliant minimum timeout was imposed on sliding-sync in (#402) which was corrected.

  • @dasha-uwu fixed admin room upgrade to work as expected. @dfuchss inspired with (#361) among many other informal reports. We appreciate the effort of everyone involved on this!

  • @tycrek reported the conduit user is involved in force-join-all-local-users commands (#373) which was fixed thanks to @dasha-uwu.

  • Thanks to @dasha-uwu bugs and compliance regarding initial_state during room creation were addressed.

v1.5.1 Breaking risk
⚠ Upgrade required
  • Until MSC2454 (#314) is implemented, all accounts using SSO/OIDC must have a local password to perform actions protected by User Interactive Authentication.
Security fixes
  • SSO/OIDC security audit uncovered multiple issues; until MSC2454 is implemented, accounts must set a password to use User Interactive Authentication (e.g., device removal).
Notable features
  • `identity_provider` config options: trusted, unique_id_fallbacks, registration, check_cookie
  • Disable password auth via `login_with_password = false`
  • Reduce btrfs space usage with `rocksdb_allow_fallocate = false`
Full changelog

Tuwunel 1.5.1

March 6, 2026

Security Fixes

  • A security audit of SSO/OIDC released with 1.5.0 uncovered several issues. We strongly advise everyone using SSO/OIDC upgrade to this release. Users should also note that until MSC2454 is implemented (tracked by #314) accounts will have to set a password to access functionality protected by User Interactive Authentication (e.g. when removing devices). We are deeply grateful to @outfrost and @exodrifter for their effort and professionalism as security researchers.

  • Case-sensitive comparisons in Room Access Control Lists were fixed by @velikopter (ruma/ruma#2358) (matrix-construct/ruma#3) (814cbc2f3).

New Features & Enhancements

  • New options for identity_provider configurations include: trusted allowing association of SSO accounts to existing matrix users (#252); unique_id_fallbacks to disable random-string users; registration to prevent registration through an IdP altogether; check_cookie for deployments that cannot use cookies.

  • Thanks to @Enginecrafter77 password authorization flows can now be disabled by configuring login_with_password = false. Clients will hide the input boxes for username and password. This option is useful for an e.g. SSO-only server. (#336)

  • Thanks to @Lymia users of btrfs will see reduced space usage if they configure the new option rocksdb_allow_fallocate = false. (#322) (PR also has links to more information)

  • Instructions for how to configure the TURN server built into Livekit and several corrections were contributed by serial documentation author @winyadepla in (#285).

  • Many users will appreciate substantial documentation by @alametti for configuring well-known and root domain delegation in (#352).

  • Thank you @the-hazelnut for updating TURN and Matrix RTC documentation with ports to be forwarded for NAT. (#305) (#306)

  • The username claim is now recognized when deciding the MXID during SSO account registration thanks to a suggestion by @aazf in (#287).

  • The max limit for /messages was increased from 100 to 1000 by @dasha-uwu which should match the limit on Synapse but with far less of a performance hazard.

  • @dasha-uwu properly optimized certain checked-math macros; other checked-math macros were also optimized for inlining.

  • Concurrent batch requests can now be made to a notary server. The default concurrency is now two, and the size of the batches have been decreased by a third. This should reduce the time it takes to join large rooms.

  • Optimization of functions which hurt performance for syncing user-presence were partially completed, though with marked improvement from before.

  • Optimization of new state-resolution functionality added during Project Hydra took place. Along with additional optimization for auth-chain gathering, CPU use for large/complex rooms (so-called "bad rooms") has been greatly reduced.

Bug Fixes

  • Special thanks to @hatomist for fixing an error which changes a users's account-type when they set a password (#313). This impacted LDAP and some SSO users. We apologize for the inconvenience this may have caused.

  • We appreciate effort by @Jeidnx for addressing various issues with SSO/OIDC Identity Provider configuration in (#281). Also noteworthy was the idea to derive the callback_url from other parameters by default rather than explicitly requiring it. Thanks to @Magnitaizer for reporting initially in (#276).

  • Thanks @VlaDexa for fixing the missing output formatting for the oauth delete command. (#321)

  • Thank you @risu729 for updating the default port number in the docker run command documentation. (#298)

  • Thank you @Lamby777 for removing an errant version field in the docker-compose example. (299)

  • Thank you @cornerot for updating the docker-compose with-traefik which still said Conduit instead of Tuwunel after all this time. (#308)

  • Thank you @exodrifter for fixing errors and typos in the MatrixRTC documentation (#343) based on a report by @RhenCloud (#338).

  • Thank you @wuyukai0403 for proofreading and fixing a typo in the troubleshooting document. (#312)

  • A report by @BVollmerhaus lead to the reopening of (#240) to use Livekit/lk-jwt-service when federation is disabled. This was re-resolved by @dasha-uwu in (b79920a).

  • Thanks to @Jeidnx for identifying a missing SSO redirect route in (#290) which was fixed in (matrix-construct/ruma@0130f6a).

  • We appreciate the panic report by @Spaenny in #296 which occurred during SSL-related upgrades on the main branch. Fixed by @dasha-uwu (87faf81).

  • Thanks to report (#302) by @data-niklas whitespace in the configured client_secret_file is now properly ignored thanks to @dasha-uwu (6f5ae17).

  • After @Giwayume reported in (#303) that URL previews failed for some sites, an investigation by @dasha-uwu discovered Tuwunel's User-Agent header required some adjustment.

  • @dasha-uwu refactored the Unix socket listener with main-branch testing by @VlaDexa (#310) and follow-up fixes in (488bd62).

  • @jonathanmajh reported in (#315) and @wmstens simultaneously reported in (#318) that admin status was not granted to the server's first user when registering with SSO/OIDC. This was fixed by (e74186a).

  • After a report by @tcyrus in (#328) that the RPM postinst script is not properly creating the tuwunel user. This was fixed by @x86pup in (5a55f84).

  • Thank you @cloudrac3r for reporting in (#330) that events were being unnecessarily sent to some appservices. This was fixed by @dasha-uwu in (d073e17).

  • Thanks to the report in (#331) by @BVollmerhaus the first registered user is not granted admin when originating from an appservice. Fixed by @dasha-uwu in (9dfba59).

  • The report by @rexbron in (#337) discovered that some distributions set modest limits on threads per process. On many-core (32+) we may exceed these limits. The RLIMIT_NPROC is now raised (9e09162) to mitigate this.

  • @x86pup set ManagedOOMPreference=avoid due to systemd not recognizing pressure-based deallocation with madvise(2) is not an out-of-memory condition.

  • @dasha-uwu removed unnecessary added delays in the client endpoint for reporting.

  • Server shutdown did not properly indicate offline status of the conduit user due to a recent regression, now fixed.

  • @dasha-uwu fixed logic issues in the client /members query filter. These same logic errors were also found in Synapse and Dendrite.

  • @dasha-uwu fixed the missing advertisement for org.matrix.msc3827.stable in client /versions.

  • Custom profile fields were sometimes being double-escaped in responses to clients due to a JSON re-interpretation issue which is now fixed.

  • @dasha-uwu fixed checks related to canonical aliases (0381547c5).

  • @dasha-uwu relaxed the encryption_enabled_by_default_for_room_type "invite" option to not match all rooms.

  • @x86pup fixed an issue with display_name and avatar_url omitted in /joined_members (fixed in our Ruma).

  • Event processing of missing prev_event's are no longer interrupted by an error from a sibling prev_event. This reduces CPU use by not repeating event processing before it would otherwise succeed.

v1.5.0 Breaking risk
⚠ Upgrade required
  • Minimum Rust compiler version (MSRV) raised to 1.91.1
  • Configuration change: `client_secret` for SSO Identity Provider can be read from a separate file (recommended secure practice)
Notable features
  • MSC2815: configurable redacted event retention (default 60 days) with retrieval for room admins
  • MSC3706: improved performance and reliability of federation joins
  • Secure limited-use registration tokens via new `!admin token` commands
Full changelog

Tuwunel 1.5.0

January 31, 2026

New Features & Enhancements

  • SSO/OIDC support. This feature allows users to register and login via authorizations from OIDC Identity Providers. For example, you can now use your GitHub account to register on the server. Tuwunel implements the OIDC client protocol directly. This is referred to as "legacy SSO" in the Matrix specification; Matrix client support is widespread. Credit to @samip5 for opening the feature-issue (#7), the most 👍 feature of the project.

  • MSC2815 has been implemented, allowing configurable redacted event retention and retrieval by room admins. The content of redacted events is persisted for sixty days by default. Redacted events can be viewed using Gomuks.

  • Secure limited-use registration token support was implemented by @dasha-uwu building off earlier work by @gingershaped in (56f3f5ea154). Use this feature with the new !admin token set of commands.

  • An outstanding major rework of the presence system by @lhjt in (#264) coordinates conflicting updates from multiple devices and further builds on push suppression features first introduced by @tototomate123.

  • MSC3706 has been implemented, improving the performance and reliability of joining rooms over federation (b33e73672b).

  • @VlaDexa implemented reading the client_secret configuration for an SSO Identity Provider from a separate file; a recommended secure practice (#256).

  • Special thanks to @winyadepla for adding highly sought Matrix RTC (Element Call) documentation for Tuwunel in (#265) and for having a kind heart to follow up with maintenance in (#270).

  • Thank you @Xerusion for documenting Traefik for deploying Tuwunel in (#259). This will save a lot of time and headache for many new users!

  • At the request of @ChronosXYZ in (#260), @dasha-uwu implemented a configurable feature to include all local users in search results, rather than limiting to those in public or shared rooms (95121ad905fb).

  • Thanks to a collaboration by @x86pup and @VlaDexa working through Nix maintenance we can now upgrade the MSRV to 1.91.1 (#275).

  • Thank you @scvalex for updating the README indicating Tuwunel is in stable NixOS (#233).

  • Thank you @divideableZero for updating the README with great news about an Alpine Package (#248).

  • Storage hardware characteristics for mdraid devices on Linux are now detected. On these systems we can now shape database requests to increase performance above generic defaults.

  • EdDSA is now a supported algorithm for JWT logins. Thank you @vnhdx for the excellent report in (#258).

  • Optimizations were made to maximize concurrency and cache performance when gathering the auth_chain.

  • An admin command to manually remove a pusher is available (note: not intended for normal use).

  • An admin command to list local users by recent activity was added.

Bug Fixes

  • LDAP users are now auto-joined to configured rooms upon creation. Thank you @yefimg for (#234), we especially appreciate help from domain-experts on these features.

  • A surgical fix by @kuhnchris in (#254) addressed a pesky bug where LDAP logins would result in admin privileges being removed for the user. Thank you @foxing-quietly for reporting in (#236).

  • @OptimoSupreme fixed issues with unread notification counting, including eliminating one of the last remaining non-async database calls in the codebase in (#253).

  • @x86pup fixed linker issues for platforms without static builds of io_uring. Thanks @darix for reporting in (#238).

  • @x86pup fixed compatibility for our optimized jemalloc build on macOS (#239).

  • @dasha-uwu made Livekit operate properly even when federation is disabled (b5f50c3fda3). Thank you @apodavalov for reporting in (#240).

  • Thank you @VlaDexa for updating the Cache-Control header to cache media as private which is more appropriate now in the Authenticated Media era.

  • Appservices now receive events properly matching on the sender MXID's localpart thanks to @dasha-uwu (c5508bba58d0).

  • Additional PDU format and compliance checks were added by @dasha-uwu (7b2079f71499).

  • Codepaths in sync systems which assumed device_id from appservices were fixed by @dasha-uwu.

  • Auto-joining version 12 rooms was inhibited from a bug fixed by @dasha-uwu in (7115fb2796f).

  • Thank you @x86pup for updating our ldap3 dependency with SSL/TLS enhancements in (#243) and fixing errors reported by @fruzitent in (#108).

  • Thanks to @x86pup join_rule is now properly defaulted in /publicRooms responses in (#244); additional compliance tests now pass!

  • Thank you @bdfd9 for reporting a regression where tracing spans around registrations did not filter out passwords from the list of fields.

  • The timezone and extended profile features were not correctly stabilized last summer and the m.tz field was incorrectly labeled tz. Thank you @bunnyblack:matrix.org for reporting in #tuwunel:matrix.org.

  • @dasha-uwu fixed git tags not being pulled and applied to CI builds (eadc9e782d8).

  • @dasha-uwu fixed a bug in sliding-sync which may result in lost invites (fd519ff7f174).

  • since tokens in legacy sync are now clamped to a maximum when the client sends a value greater than expected, preventing a possibility of missing events during the request.

  • Media deletion commands which are time-based suffered a bug from incorrect creation timestamps on some filesystems. This was resolved by exclusively using the mtime attribute, which is acceptable because Matrix media is immutable.

  • Queries for the deprecated _matrix._tcp SRV record have been reactivated due to an ineffective and unenforced sunset by the specification and other implementations.

  • Thank you @x86pup and @dasha-uwu for various maintenance and linting efforts for the latest rustc versions and in general.

Honorable Mentions

  • Please take a moment to recognize how lucky we are to have @scvalex as our NixOS package maintainer. From having the wherewithal to rise above the noise and lend this project trust from the very first days, time and again this gentleman has gone above and beyond on our behalf. Thank you @symphorien at NixOS as well for the patch applied surgically in https://github.com/NixOS/nixpkgs/pull/462394.
v1.4.9.1 Security relevant
⚠ Upgrade required
  • All federating deployments must upgrade immediately for the security mitigation.
  • Apply this off‑schedule release before the next scheduled update.
Security fixes
  • Federation responses now validate input before trusting, signing, and disseminating events from remote servers; addresses follow‑up vulnerabilities similar to CVE addressed in 1.4.8.
Full changelog

Tuwunel 1.4.9

December 30, 2025

All federating deployments must upgrade for follow-up mitigations similar to those patched by 1.4.8 now uncovered as a wider class of vulnerabilities in additional locations. This is an off-schedule coordinated security release. Full release notes will be included with the next scheduled release.

Security Fixes

  • Federation responses processed from a remote server assisting in membership state transitions lacked input validation: trusting, signing, and disseminating an event crafted by the remote server. These vulnerabilities were uncovered in a classic follow-up to the initial forgery attack pattern described in patch 1.4.8 also present in additional locations.

Beta — feedback welcome: [email protected]