Releases: wardcore-dev/onyx-server
beta 0.3
v0.3-beta
Security
-
Path traversal in media file handling (
media/local.rs)
User-supplied filenames from URL path were passed directly intoPathBuf::joinwithout sanitization, allowing requests like/../../../etc/passwdto escape the storage directory.
Fixed by rejecting filenames containing/,\, or.., and verifying the canonicalized path stays within the storage root. -
Unbounded nonce store DoS (
auth.rs,handlers/auth_handlers.rs)
Challenge nonces were stored in an unboundedHashMapwith no expiry, allowing an attacker to grow server memory indefinitely by looping/auth/challenge.
Fixed by attaching a timestamp to each entry (TTL: 60s), pruning expired entries on every insert, and capping the store at 10,000 entries. Expired nonces are now rejected in/auth/verify. -
Partial token exposure in logs (
auth.rs,handlers/auth_handlers.rs)
The first 16 characters of the auth token were logged on 401 responses and on successful registration, risking credential leakage via log aggregators or shared environments.
Fixed by removing token content from all log output. -
Timing side-channel on password hash comparison (
handlers/auth_handlers.rs)
Password hashes were compared with standard string equality, which short-circuits on the first differing byte and enables byte-by-byte recovery of the stored hash via timing differences.
Fixed by double-hashing both values through SHA-256 before comparison, producing fixed-length digests that eliminate timing signal. -
Auth token accepted via query string on HTTP routes (
auth.rs)
The auth middleware accepted tokens from?token=query parameters on all routes, causing tokens to appear in proxy logs, browser history, andRefererheaders.
Fixed by restricting the HTTP auth middleware toAuthorization: Bearerheaders only. The/data/media/:filenamedownload route retains?token=support as a deliberate exception — client image/media widgets cannot set custom headers when loading a URL directly. -
Invite token exposed on unauthenticated endpoint (
handlers/info.rs)
GET /groupis a public, unauthenticated route that returnedinvite_tokenin its response, allowing anyone with network access to extract the token and bypass invite-only access control.
Fixed by removinginvite_tokenfrom theGET /groupresponse entirely. On the authenticatedGET /groupsroute,invite_linkis now returned only to users with theownerormoderatorrole. -
File type bypass via client-supplied Content-Type (
handlers/media.rs)
File type validation relied on theContent-Typeheader supplied by the client. An attacker could upload HTML containing JavaScript with a spoofedContent-Type: image/png, achieving stored XSS when the file was later served.
Fixed by detecting the actual file type from magic bytes, ignoring the client-supplied header entirely. Download responses now includeX-Content-Type-Options: nosniffandContent-Disposition: attachmentto prevent browsers from rendering served files inline.
Features
-
Rate limiting enforced (
rate_limit.rs,handlers/messages.rs,server.rs)
max_messages_per_minuteandmax_joins_per_minutewere defined in config but never checked anywhere in the codebase.
Implemented a per-user sliding window rate limiter. Limits are now enforced at the start of the/send,/groups/{id}/send, and/groups/join/{token}handlers. -
Configurable CORS policy (
config.rs,server.rs)
CorsLayer::permissive()was hardcoded, allowing requests from any origin regardless of deployment context.
Addedsecurity.allowed_originsto config. Resolution order: explicit origins list →server.public_url→ permissive fallback (appropriate for LAN and native client deployments).
beta 0.2
Changelog:
- Fixed a bug related to uploading large files.
beta 0.1
v0.1-beta init