The hardening release: what four review passes over the whole project turned up, each finding verified before it was fixed. Drop-in — no migrations, no new environment variables. Three things change on their own: a password-less instance reached through a forwarder that terminates on loopback (ssh -L, kubectl port-forward, a bare proxy_pass) is asked for the setup token like any other network caller; MQTT publishes a latency nobody measured as null rather than 0 ms; and the Windows installer keeps every non-administrator account out of C:\ProgramData\MySpeed.
✨ New
- Last failure — the enlarged test overview dates the newest failed test beside the longest streak.
🔒 Security
- The Windows installer locks the data folder —
C:\ProgramData\MySpeedinherited read access for every local account, database, TLS key and.envincluded. Both folders now grant SYSTEM and Administrators alone. - Password-less access needs a local name as well as a local socket —
ALLOW_NO_PASSWORD=truestill waives everything, and a console or healthcheck askinglocalhostor127.0.0.1is unaffected. - The node proxy is a proper hop — hop-by-hop headers and a
content-encodingthe parent already inflated are stripped before forwarding, so a chunked or gzipped request no longer reaches a node carrying two framings; storage requests routed through a node are metered like the ones made directly; a node password holding a control character is kept out of the raw header, and a restore refuses the row, instead of every proxied request under that node answering 500. - Outbound fetches are bounded — the server-list and update-check fetches refuse a redirect and stop reading past 5 MB, and a librespeed server on a link-local or cloud-metadata address is refused when the target is saved. LAN servers are unaffected.
- The rate limiter keys every spelling of one address the same — the elided, zero-padded and IPv4-mapped forms of one caller were separate budgets.
/api/healthhas a limit of its own, far above any prober. - The install scripts check what they run —
chooser.shanddocker-install.shfetch to a checked file and refuse an HTTP error instead of executing it as root.
🐛 Fixes
- The Windows installer upgrades in one run — the exe carried Bun's version resource rather than MySpeed's, so an upgrade built with an older Bun than the last one kept the file it found and then removed it with the old product; the service started into nothing and the installer rolled back after four minutes, which is what withdrew 1.5.3 minutes after it went up. The exe now carries MySpeed's own version.
- The x64 baseline builds are baseline again — Bun 1.4.0 ships its baseline runtime as a copy of the AVX2 one, so the v1.5.2
MySpeed-linux-x64-baseline, the Windows baseline installer and the Docker image all crashed on a pre-AVX2 CPU. Every build is on Bun 1.3.14, and a release refuses two assets with one digest. - The Windows service restarts ten seconds after a crash, as the install page always said; it carried no failure actions at all.
- A latency nobody measured is unmeasured everywhere — the result card, the detail pane, the latest-test card and the node card show N/A in blue rather than 0 ms in green, the ping chart's average skips it, the OpenGraph card shows the window's throughput instead of no image, and MQTT publishes
null. The speed charts' average now counts a run that connected and delivered nothing. - Under
BASE_PATH— a browser holding a stale session cookie beside a live one is no longer shown the password prompt, and two MySpeeds behind different prefixes on one origin stop sharing the chosen node, theme, language and preferences. - A restore judges what it is given — a test on a date that does not exist (
2026-02-30) or more than two days ahead of the clock is skipped rather than rolled into March or quoted as the latest test for good; a node row is checked before it is written, the way a target row already was; a refused configuration restore leaves the storage dialog open; a hand-edited retention beyond the cap is refused with one warning rather than 1440 a day. - A factory reset resumes a paused instance — it came out "factory fresh" still paused, with every scheduled run silently skipped.
- The interface says what it does not know — a refused
/storagereads "not known" rather than "0 KB and 0 tests", the status bar says "last test unknown" when the list could not load rather than "no test has run yet", the integrations dialog says why it failed to load and offers a retry, and removing the password on a preview instance reports the read-only refusal itself. - Statistics — the high-resolution chart no longer keeps the previous range's series when its request fails, nor drops back to the downsampled series when the comparison toggles; the axis ticks and the 12-hour suffix follow the interface language rather than the browser's; the transfer totals count byte counts stored as text; the compare picker sits at the right edge on a single-target instance; the digest's failure streak is printed in the configured timezone.
- Accessibility — toasts are announced to screen readers, the integration dialog's save and delete buttons have names, the second saying it is armed, and a menu no longer closes on an Escape meant for the dialog above it.
- Smaller edges — the alert and confirm buttons a dialog names itself read in the interface language; a Discord template of only whitespace sends the default line rather than being refused; the database size prints in a real unit; a row whose timestamp cannot be read shows a blank, not
NaN:NaN; a run against an impossible target id answers 400, not 500; a DEL byte in an ntfy title or InfluxDB token is dropped rather than failing the send;uninstall.sh --keep-dataworks under dash,install.shmatches the unit name whole, anddocker-install.shsays when the Compose plugin is missing.
Five new interface strings ship translated in all 23 languages, written here rather than through Crowdin, so they are worth a translator's eye.
Downloads
| Platform | x86-64 | ARM64 |
|---|---|---|
| Windows | EXE · MSI · EXE (no AVX2) · MSI (no AVX2) | |
| Linux | Binary · No AVX2 | Binary |
| macOS | Binary | Binary |
Source Distribution
- ZIP Archive (requires Bun runtime)
Docker Images
i7gamer/myspeed:latesti7gamer/myspeed:1.5.4