This release includes 2 security fixes for security teams reviewing exposed deployments.
Topics
Affected surfaces
Summary
AI summaryBroad release touches Tooling & docs, Reliability, ✨ Highlights, and Connectivity.
Full changelog
A ground-up rebuild of how FileSync connects and saves files — native WebRTC, a built-in signaling server, and true streaming-to-disk for transfers of any size.
This is a major release. FileSync no longer depends on PeerJS: connection setup is now handled by a lightweight first-party signaling server bundled with the app, and received files stream straight to disk so even multi-gigabyte transfers stay memory-safe.
[!IMPORTANT]
Upgrading from 3.x requires re-downloading the compose files (docker-compose.yml, and for HTTPS thedocker-compose-ssl.yml+Caddyfile). Pulling the new image alone is not enough — see Upgrading.
✨ Highlights
- 🔗 Native WebRTC — PeerJS is gone. Smaller footprint, fewer moving parts, no third-party connection broker.
- 📡 Built-in signaling server — served by FileSync itself at
/ws. Nothing extra to run; it relays only connection setup and never sees your files. - 💾 Streaming downloads, any size — files are written to disk as they arrive, so memory stays flat even on multi-GB transfers.
- 🩺 Redesigned diagnostics page at
/test.html— light/dark, an at-a-glance verdict, and a one-click connectivity report to share with support. - 🛡️ Hardened for production — required secret at startup, rate-limited credentials, a self-healing container, and self-hosted fonts.
🚀 What's new
Connectivity
- Native
RTCPeerConnection/RTCDataChannelclient replacing the PeerJS wrapper. - First-party WebSocket signaling relay (
/ws) with rate limiting, idle timeouts, and capacity guards. - Relayed transfers now work correctly behind Docker — TURN relay candidates are rewritten in transit so peers on different networks get a reachable address.
Transfers
- Chunked, backpressured protocol that keeps both sender and receiver memory bounded.
- Three save methods, auto-selected per browser:
| Method | When | Notes |
|---|---|---|
| File System Access | Desktop Chrome/Edge/Brave/Opera (HTTPS) | Streams straight to a file you pick |
| Service Worker | All modern browsers (HTTPS) | Streamed browser download, memory-safe |
| Blob | Fallback / plain HTTP | Buffered in memory (~500 MB practical limit) |
Reliability
- Serialized disk writes — fixes a File System Access corruption case on fast/large transfers.
- Transfers no longer hang if a peer drops mid-send; abort, remove, and "cancel all" now tear down cleanly (no leaked connections or stuck downloads).
- Transient network blips are tolerated instead of killing an in-progress transfer.
- The container self-heals: if the backend process dies, it restarts instead of serving a half-dead app.
Security
- The server refuses to start without
SECRET_KEY(used to sign TURN credentials and tokens). /api/credentialsis rate-limited; CORS is off by default (opt-in viaCORS_ORIGINS).- Fonts are self-hosted — no third-party font CDN, satisfying the app's strict Content-Security-Policy.
Tooling & docs
- End-to-end Playwright test harness covering browsers × save methods × connection modes.
- Dependabot for Python, Docker, GitHub Actions, and the test harness.
- README refreshed: how connections are made, the required ports, and how files are saved.
⚠️ Upgrading from 3.x
The compose files changed — re-download them.
-
Re-download the deploy file(s) for your setup:
- HTTP →
deploy/docker-compose.yml - HTTPS →
deploy/docker-compose-ssl.yml+deploy/Caddyfile
- HTTP →
-
Set your secret (now required — the app won't start without it). Generate one:
python3 -c "import secrets, base64; print(base64.b64encode(secrets.token_bytes(32)).decode())"Replace both
<SECRET_KEY>placeholders in the compose file. -
Open the required ports (below) if you haven't already.
-
Pull and restart:
docker compose pull && docker compose up -d
💡 No separate PeerJS server is needed anymore — if you ran one, you can decommission it.
📋 Required ports
| Port | Protocol | Purpose |
|---|---|---|
| 80 / 443 | TCP | Web interface (HTTP / HTTPS) |
| 3478 | TCP + UDP | STUN/TURN — connection setup |
| 50000–50100 | UDP | TURN relay range (used when a direct path isn't possible) |
Full changelog: https://github.com/polius/filesync/compare/v.3.7.0...v.4.0.0
Breaking Changes
- PeerJS dependency removed; native WebRTC (`RTCPeerConnection`/`RTCDataChannel`) replaces it.
- Required `SECRET_KEY` environment variable at startup – the server refuses to start without it.
- Compose files changed: re‑download `docker-compose.yml`, `docker-compose-ssl.yml`, and `Caddyfile` for upgrade; pulling only the new image is insufficient.
Security Fixes
- Server requires `SECRET_KEY` for TURN credential signing; without it the process aborts (prevents unauthenticated access).
- Rate‑limited `/api/credentials`, CORS disabled by default (`CORS_ORIGINS` opt‑in), and self‑hosted fonts enforce strict CSP.
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
Related context
Related tools
Beta — feedback welcome: [email protected]