github kimusan/Tachyon v4.4.7

8 hours ago

The last three of the back-button regressions, two of which only show on a large mailbox or on a phone. Plus the end of the admin password error on Docker upgrades, calendars that could never be removed, and a way to log logins on their own.

Worth taking if you run the Docker image, because it is rebuilt on PHP 8.2.35 and the 4.4.6 one is not, or if your inbox holds more than 10,000 messages, because no conversation could be opened in one at all.

Security

  • The Docker image is rebuilt on PHP 8.2.35. Upgrade it. The 4.4.6 image shipped 8.2.34, which carries CVE-2026-109618 and CVE-2026-109619, both rated critical and both ending in remote code execution: the first because an out-of-memory error exits through longjmp() and leaves request memory in a state shutdown then reads, the second because global state a worker keeps between requests is read after the memory it points at has been freed. Neither is anything Tachyon does, and nothing in the application can guard against them. The application is unchanged; the image is rebuilt on the current php:8.2-fpm-alpine, which is 8.2.35 on both amd64 and arm64, plus one Dockerfile line to get past an Alpine musl revision that broke the build for a few hours. If you pulled v4.4.7 or latest on the day it was tagged you have the 8.2.34 image and want to pull again; docker run --rm ghcr.io/kimusan/tachyon:v4.4.7 php --version settles it. Caught by @a01fe. If you installed from the tarball or the Debian package instead, this release does nothing for you and you want your distribution's PHP 8.2.35, 8.3.36, 8.4.27 or 8.5.12. Reported by @limolitz (#166)

Fixed

  • No thread could be opened in a folder holding more than message_list_limit messages, 10,000 by default, which showed as the full folder under a "Back to message list" button. That branch answers with the most recent slice rather than working out the whole uid list, and says in its own comment that it does not use THREAD; a request naming one thread fell into it and got the unthreaded folder back, with the thread uid still echoed in the response. It could not escape either, because the one thing that lifts the limit is a cached uid lookup that is itself skipped whenever a thread is named. A mailbox growing past 10,000 messages was enough to turn this on, which is why it had worked for years and why the IMAP server was never at fault. Reported by @floppybl (#156)
  • The whole folder sat on screen, with no spinner, while a thread loaded. The test that drops the messages on screen when they no longer answer the request compares the folder, the search and the offset. Entering a conversation changes none of those from page 1, so nothing was dropped and the old list stayed there until the thread arrived. On a large mailbox that is indistinguishable from the thread never loading. From page 2 or later it did clear, because the offset moved, which is what made it look intermittent (#156)
  • Moving to the next message across a page boundary flashed the next page's list, on mobile, where the list and the message are separate views rather than side by side. Crossing a boundary calls gotoPage(), which writes an address with no message in it, and the back-button work in 4.4.3 taught the route to read that as "close the message". The route now leaves the open message alone for the one dispatch where a selection is already pending. Reported by @lvarnava (#157)
  • A Docker upgrade reported an admin password failure on every restart, on an installation where nothing was wrong and nothing needed doing. The entrypoint treated a missing admin_password.txt as a failure without asking whether a password was already configured, and on an existing installation that file is legitimately absent: it is written once, on the first run, and an administrator who read it and deleted it, which is the sensible thing to do with a password in clear, ends up in the same position as one who set their own. Three cases now, and only the last of them can fail. Reported by @jon4156 (#158)
  • A CalDAV calendar could not be removed once it had been seen. The code that stores a discovered calendar only ever inserted or updated it, and nothing anywhere deleted one, so moving the URL from a single public collection to the DAV root left the old collection sitting next to the new ones for ever. A sync now reconciles what is stored against what discovery returned. A calendar missing from the listing is hidden at once, and its events are removed only after a second sync confirms it, because a PROPFIND answers per collection and one the server refuses while answering for the others is indistinguishable from one the user deleted. Clearing the URL, or setting sync to No, removes them all on save. Reported by @Quiwy (#164)

Changed

  • A login can now be logged without logging every request. A successful login wrote nothing to the main log at all, so it could only be seen at level 6, among the per-request traffic; it is a notice now, at level 5. A failed login went only to the fail2ban file and to LOG_AUTHPRIV, both off by default, so the ordinary log could not tell a failure from no attempt at all; it is a warning, which is visible at the default level of 4. Both carry the ip and the login through the same substitutions the fail2ban format already uses, so nothing new is exposed and no password goes near them. Worth knowing before upgrading: an installation with logging enabled therefore starts recording the client ip and the login for failed attempts. Asked for by @dionysius (#163)
  • The syslog driver sent everything at LOG_INFO. It pinned its own level in the constructor, so an error and a debug line arrived at the same priority and filtering by priority did nothing at all. Driver::Write had the severity the whole time and dropped it before handing the message over; the driver signature now carries it through to syslog(). Found in #163
  • Translations updated for French and Polish

Don't miss a new Tachyon release

NewReleases is sending notifications on new releases.