| Name | Modified | Size | Downloads / Week |
|---|---|---|---|
| Parent folder | |||
| wekan_10.47_amd64.snap | 2026-07-28 | 397.4 MB | |
| wekan-10.47-riscv64.zip | 2026-07-28 | 312.7 MB | |
| wekan_10.47_arm64.snap | 2026-07-28 | 305.7 MB | |
| wekan-10.47-s390x.zip | 2026-07-28 | 315.0 MB | |
| wekan-10.47-ppc64le.zip | 2026-07-28 | 314.1 MB | |
| wekan-10.47-sandstorm.spk | 2026-07-28 | 171.2 MB | |
| wekan-10.47-mac-arm64.zip | 2026-07-28 | 307.8 MB | |
| wekan-10.47-amd64.zip | 2026-07-28 | 309.0 MB | |
| wekan-10.47-arm64.zip | 2026-07-28 | 311.7 MB | |
| README.md | 2026-07-28 | 6.7 kB | |
| v10.47 source code.tar.gz | 2026-07-28 | 33.4 MB | |
| v10.47 source code.zip | 2026-07-28 | 34.6 MB | |
| Totals: 12 Items | 2.8 GB | 0 | |
v10.47 2026-07-28 WeKan ® release
This release fixes the following SECURITY ISSUES found by GitHub CodeQL code scanning:
Trust a certificate instead of disabling verification, and escape every metacharacter. Thanks to GitHub CodeQL code scanning and xet7.
**Alert [#430], `js/disabling-certificate-validation`, High**: `reqOptions.rejectUnauthorized = false` in the outgoing-webhook path. It is right, and the switch is gone. `rejectUnauthorized: false` accepts ANY certificate — including the one a man in the middle presents — which is the attack the TLS handshake exists to stop. What the reports behind it actually need is not "verify nothing", it is "this certificate is legitimate", so that is what WeKan takes now: `WEBHOOK_TLS_CA_CERT` (the certificate or CA to TRUST for outgoing webhooks), `MAIL_TLS_CA_CERT` (the same for the mail server) and `MAIL_TLS_SERVERNAME` (the name to verify the mail certificate AGAINST, for a wildcard that covers one level fewer than the host has). Each is the PEM itself or a path to a file holding it. A self-signed certificate is its own issuer, so naming it here is exactly what makes it valid — and verification stays ON, the chain is still checked, the hostname is still checked. A path that cannot be read is not fatal: it says which setting failed and keeps the system trust store. The SSRF protections are untouched — the address is still resolved once and pinned, private ranges are still refused, redirects are still blocked. **Alert [#429], `js/incomplete-sanitization`, High**: a test escaped dots only when building a regular expression, so a backslash in the value could change the meaning of the pattern it was spliced into. It escapes every metacharacter now, the backslash first, with the helper the other test files already use.and fixes the following bug:
A rejected promise no longer ends the whole server when the database is busy. Thanks to Nissulya and xet7.
The snap that was restarting in a loop (#6533) showed the earlier fixes working. It also showed the server dying regardless: SyncedCron: Fatal error encountered (unhandledRejection): ValidationError: ... sqlite.(*collection).UpdateAll ... database is locked (5) (SQLITE_BUSY) SyncedCron: Received UNHANDLED_REJECTION signal - cleaning up running jobs systemd: Main process exited, code=exited, status=1/FAILURE `quave:synced-cron` installs a process-wide `unhandledRejection` handler that calls `process.exit(1)`. So ANY unhandled rejection — including one write losing a race for the SQLite write lock, which is transient by definition — killed the whole server, and systemd restarted it into a database the restart had made busier. The restart counter reached 73. WeKan takes that decision back. The package is deliberately polite about it: it only cleans up and exits `if (process.listenerCount('unhandledRejection') === 1)` — when nothing else has an opinion — so having one is the documented way to stop it. A transient database error is logged and recorded for Admin Panel / Problems and WeKan keeps serving; anything else is logged with its full stack and WeKan still keeps serving, because ending everybody's session over one rejected promise is a larger failure than the one being reported. An uncaught EXCEPTION still exits unless it is a transient database error: a process that threw out of a place nobody handled can be holding half-applied state. Nothing is silenced — every rejection is logged, and the database ones are counted in the `database` event stream where Admin Panel / Problems shows them.and has the following test-harness fixes:
Four guards that pinned an older shape, and a browser test that named the wrong half. Thanks to xet7.
The Visibility saves share one "is this input on screen" check now, so the guard looks at the helper rather than at each call site. `/information` redirects the FlowRouter way, like `/translation` before it. The phone rules carry `!important`, because the desktop rule they override is more specific. And "the newest release" in the changelog guard means the newest RELEASE — an Upcoming section may sit above it, it is checked by its own test, and a release needs at least ONE entry, since "more than five" measured the day's workload rather than the format. The background-image tile test waited only for `.board-list-item.has-background-image`, which cannot tell "the board has not arrived in minimongo yet" from "it arrived without the class"; under a three-browser run WebKit reported the second when it was the first. It waits for that board's own tile first, so a future failure names the actual problem.and updates the backlog:
TODO Later: ten issues closed since it was written, and what testing FerretDB on MySQL answered. Thanks to xet7.
Every issue in `# TODO Later` was checked against GitHub. Ten are no longer open and are gone from the list: [#3138], [#3252], [#3276], [#3378], [#3748], [#3828], [#4055], [#4774], [#5149] and [#6511]. The "already correct in the current code" category went with them, because it held only the two that are now closed. [#6509] — "please test FerretDB v1 with MySQL, MariaDB and SAP HANA" — is mostly answered rather than pending: the conformance harness runs one catalogue of 100 queries against every backend with an image for this machine, and **MariaDB now answers identically to SQLite on 98 of them**, the two exceptions being the `$slice` / `$elemMatch` projections that no backend implements. Getting there took a dozen fixes in the fork. MySQL's confirming run is still pending and SAP HANA is untested — its image needs a licence acceptance — and the entry says so instead of implying the whole request is done. Finnish gained `databaseReportTitle` ("Tietokantaongelmat"). The other 40 placeholders in that language are numbers, symbols, product names and a font name, which are the same in Finnish — the count of "untranslated" strings is mostly that. The search-operator abbreviations (`b:`, `l:`, `s:`) are left in English on purpose: translating them changes how a search is TYPED in that language, which is a decision for the maintainer, not a wording fix.and updates translations:
- Updated translations. Thanks to translators and xet7.