Skip to content

Release 0.38.0 - #41

Merged
Dim145 merged 1 commit into
mainfrom
release/0.38.0
Oct 25, 2026
Merged

Dim145 merged 1 commit into
mainfrom
release/0.38.0

Conversation

@Dim145

@Dim145 Dim145 commented Oct 25, 2026

Copy link
Copy Markdown
Owner

A minor release: security fixes from a review of the upstream project, a fairer sign-in lockout, seed time credited at its real rate, and the October 2026 major dependency updates (Node 26, Go 1.27, Tailwind CSS 4). No migrations. Several settings and one behaviour deserve a look before upgrading: see Upgrading at the end.

Security

  • Uploaded .torrent files were readable by any signed-in member through another member's upload list. Files uploaded before 0.35.0 still carried their uploader's announce URL, passkey included. The list no longer serves them, and a background sweep cleans every stored file.
  • Any member could delete or overwrite another member's peer entry by announcing under their peer_id, which every client in a swarm sees. That erased the victim's next credit, or replaced their counters and address. Each member now has an entry of their own.
  • Sign-in blacklisted whole addresses and told which usernames exist. One stranger mistyping a password behind a VPN exit or a carrier NAT locked everyone behind it out of the site. Sign-in now has its own limit per address, ten attempts in five minutes with no blacklist, and the challenge answers alike whether the account exists. An IPv6 host counts by its /64.
  • Passkey second-factor sign-ins ignored "sign out everywhere", and a lifted ban brought back cookies nobody had presented while it lasted.
  • Members could comment on and favorite torrents they cannot see.
  • Dormant accounts kept their login verifier in clear, when it was stored before encryption at rest. A background sweep re-encrypts them.
  • The reference Caddyfile kept who downloaded and announced what: client addresses beside download URLs for thirty days, and every announce with its address and peer_id. It now masks addresses in access.log and drops them, and the identifiers that link announces, from tracker.log.
  • Smaller ones: Redis connection errors printed a rediss:// password; a " in a Telegram notification link broke its markup; the tracker and the relay set X-Content-Type-Options: nosniff themselves; the api and web images give their user as 65532:65532, which runAsNonRoot can check.

Sign-in: a lockout per account that spares members' own browsers

Ten failed sign-ins in fifteen minutes hold a username out of password sign-in, from every address. That stops guessing spread across addresses. On its own, it would also let anyone who knows a username keep its owner out. So a browser that completes a sign-in now receives a known-device cookie (trackarr_kd, six months), and the account's count does not apply to it: a member's own browsers keep signing in. The cookie skips nothing — not the password, not the second factor — and "sign out everywhere", a ban or a password change voids every one at once. The sign-in page says which limit was hit.

Seeding and the tracker

  • Seed time was credited at half the real rate, which doubled every hit-and-run requirement. It is credited in full now.
  • Hit-and-runs were flagged only when a moderator ran the check by hand. A sweep now runs every ten minutes, and only flags a member who downloaded something.
  • left=0 got around the minimum ratio and earned seed bonus. A seeder is now told about leechers only, and the bonus pays peers seen within the hour.
  • A Redis outage refused every announce, and the API gave up on Redis for good after eleven seconds without it. The tracker now answers in a degraded mode, without a peer list, and the API reconnects however long the outage lasts.
  • Bonus events lapsed whenever nobody visited the site for five minutes, and a scheduled event began at the first page view after its start. A one-minute sync keeps them running on time.
  • BitTorrent v2 and hybrid torrents came out of the upload with their piece layers re-keyed, so a v2 client could not verify a piece. Uploads and downloads now edit the file without decoding it, and the sweep repairs stored files.
  • Default installs advertised a UDP tracker nothing served: every .torrent carried a UDP tier no listener answered. UDP is now off unless enabled, in the tracker and the API alike.
  • A member holds at most five live peer entries per torrent; a malformed passkey is refused before any lookup, and an address that keeps failing is answered from memory; an announce has a five-second deadline; the minimum ratio is not enforced during an event that counts no download.

Also fixed

  • A panic restore could become impossible to complete after a single write during the panic, or one interrupted restore.
  • The site rules and the welcome note were editable in Admin → Branding and shown nowhere. The footer linked to the upstream author's sites.
  • NUXT_SESSION_SECRET_FILE and the other *_FILE secrets passed the boot check and were then ignored.
  • The registration proof of work gave the browser 60 seconds, which failed about one registration in six on a phone. It now gets four minutes.
  • Three pages showed a generic error instead of the server's: saving a search past the cap, signing out everywhere on a revoked session, and the fields an upload rule refused.

Platform

Node 26 and pnpm 12, Go 1.27, TypeScript 6 and Tailwind CSS 4 (the interface is unchanged, except date inputs that are now as tall as the text inputs beside them). In the compose file, PgBouncer 1.26.1, whose security fixes reach this stack, Redis 8.10.2 and Caddy 2.11.7. In the Helm chart, the CloudNativePG, Valkey and RustFS subcharts (RustFS moves from a beta to 1.0.3), externalRedis.tls for a Redis reached over TLS, and resources for Valkey's init container.

Verified

Typecheck, the API's 630 unit and 486 integration tests, the web's 1,245 unit tests, the tracker and the relay under the race detector, helm lint and the chart's render checks, the six images, and the end-to-end suite (558 checks over 14 scenarios). A container scan of the tree (semgrep, trivy, gitleaks, gosec, hadolint, actionlint, zizmor, govulncheck, osv-scanner) reports nothing left untriaged.

Upgrading

Swap the six images and, with Docker Compose, take the new docker-compose.prod.yml and docker/caddy/Caddyfile (new PgBouncer, Redis and Caddy tags, and the log changes above). With Helm, run helm dependency update for the new subcharts. No migrations.

  • UDP is off unless you enable it, in the API as well. If you serve UDP announces, set TRACKER_UDP_ENABLED=true (Compose hands it to both the tracker and the API) and NUXT_PUBLIC_TRACKER_UDP_URL; with Helm, tracker.udp.enabled: true and site.trackerUdpUrl. Otherwise .torrent files no longer carry a UDP tier.
  • Hit-and-run now flags on its own, from two minutes after boot. Seed time banked before this release was credited at half rate and is not recomputed, so the first sweeps may flag members who did seed long enough: look at the moderation queue after upgrading.
  • Uploads from before 0.35.0 exposed their uploader's passkey to signed-in members. If your instance is that old, have those uploaders replace their announce passkey, or reset it for them from the admin panel.
  • NUXT_SESSION_SECRET must be at least 32 characters: a shorter one now stops the API at boot, where it used to fail every sign-in. ADMIN_API_KEY was documented as required; no route uses it, and the reference now says so.
  • The previous access.log and tracker.log keep what they recorded; rotate or delete them if that matters to you.
  • Two sweeps run in the background after the first boot, both resumable: stored .torrent files (200 a minute) and credentials still encrypted under an old key or not at all (500 a minute).
  • ANTICHEAT_MAX_BYTES_PER_SECOND (80 MiB/s by default) is now read: uploads faster than that are flagged for review, never refused.

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Dim145
Dim145 merged commit b435a73 into main Oct 25, 2026
11 checks passed
@github-actions
github-actions Bot deleted the release/0.38.0 branch October 25, 2026 19:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant