CypherBay

Changelog

Release History

All notable changes to CypherBay, most recent first.

PBKDF2 iterations increased to 310,000
Key derivation hardened from 100,000 to 310,000 PBKDF2-SHA256 iterations. Brute-forcing a session password now costs 3× more compute per guess. Salt prefix updated to CypherBay-v2- to prevent cross-version key collisions.
Client-side file encryption
Files are now encrypted with AES-256-GCM in the browser before upload. The server receives and stores only an opaque binary blob — no filename, no MIME type, no readable content. Decryption happens in the receiver's browser using the shared session password. Anyone with a direct file URL sees random bytes.
Inline image display in chat
Images now render directly in the chat bubble. While the encrypted file is fetched and decrypted, a loading spinner is shown. Once decrypted, the image appears inline. Click opens it full-size in a new tab. Videos and audio also play directly in-chat.
Self-hosted file storage replaces 0x0.st
File uploads no longer go to the external service 0x0.st. Files are stored directly on the CypherBay server under data/uploads/ with a random 32-character hex ID. Files are automatically deleted after 7 days. No third-party involvement in any part of the communication.
Landing page layout overhaul
Action buttons moved above the feature grid so they are immediately visible on load. Features now render in a 3-column grid on desktop, 2-column on tablet, single column on mobile. Cards show a green top-border accent on hover instead of a full border change.
QR codes now open on iPhone
The QR library previously only supported alphanumeric mode, which excludes the # character. Byte mode encoding was added so full URLs including the hash fragment can be encoded. Separately, the invite modal was passing only the session ID to the QR renderer instead of the full URL — iPhone Camera saw plain text, not a link.
Session cookie and invite modal
Sessions can be saved to a cypherbay_session cookie (opt-in via checkbox). A new Invite button in the chat toolbar opens a modal with a scannable QR code and copyable link and session ID. The resume-session widget on the landing page detects any saved session and offers to rejoin.
Rate limiting hardened across all endpoints
Typing events are excluded from rate limiting — previously they consumed the same bucket as messages, making it trivial to exhaust the limit without sending anything. Separate per-IP buckets now exist for send, upload, and delete. Rate limiting added to upload.php (5/min) and delete.php (10/min), which were previously uncapped.
Security audit — header injection, file locking, PHP logic
Fixed header injection in upload.php: filename was passed raw into MIME headers. Added shared file locking (LOCK_SH) when reading session files to prevent race conditions with concurrent writes. Fixed a PHP falsy-empty-array bug in send.php: if ($saved) evaluates to false for an empty array, discarding valid session state. CSP headers tightened across all API endpoints.
UI redesign and per-minute message counter
Primary text changed from neon green #39ff14 to near-white #ddeedd — green is now reserved for UI chrome and accents only. Bracket notation ([COPY], [E2E]) replaced with inline SVG icons. Chat layout fixed with proper flexbox constraints. Added a live message counter showing remaining sends before the per-minute rate limit. Polling interval increased from 1 s to 2.5 s with exponential backoff on connection errors.