Files
OwnCord/docs/security.md
T
jevb dc35f8ea4b fix: client security hardening (19 fixes across Rust + TypeScript)
Addresses findings from comprehensive security review of the Tauri client:

Critical:
- Scope fs:allow-write-file from ** to $APPDATA/**,$APPLOG/**
- Validate server_url scheme (https://) in update_commands.rs

High:
- Change CRED_PERSIST_LOCAL_MACHINE to CRED_PERSIST_ENTERPRISE (per-user)
- Remove password from IPC response (#[serde(skip)] on CredentialData)
- Auto-login uses stored token instead of password
- Gate open_devtools behind #[cfg(feature = "devtools")] at registration
- Validate remote_host for CRLF/null in livekit_proxy
- Guard icons.ts innerHTML with runtime check
- Add file upload MIME type allowlist
- Clear pendingTotpPartialToken after use

Medium:
- Add sandbox attribute to YouTube iframes
- Remove image/svg+xml from SAFE_MIME_TYPES
- Strip trailing punctuation from linkified URLs
- Validate host format in api.ts setConfig
- Cap error messages at 200 chars (anti-phishing)
- Rate limit search requests (500ms interval)
- Validate Tenor GIF URLs against trusted origins
- Sanitize notification titles (control chars + length cap)
- Validate ptt_set_key vk_code range (1-254)
- Add host validation to store_cert_fingerprint

Docs:
- Add "Client Security Hardening" section to docs/security.md
2026-03-31 19:11:36 +02:00

101 lines
5.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Security Policy
Security guidelines and vulnerability reporting for OwnCord.
## Reporting Vulnerabilities
Use GitHub Security Advisories to report vulnerabilities: go to Settings > Security > Advisories and create a new advisory.
**Do NOT open public issues for security bugs.**
## Response Timeline
- **Acknowledgment:** Within 48 hours
- **Critical fixes:** Within 7 days
- **Non-critical fixes:** Included in the next release
## Two-Factor Authentication
OwnCord supports TOTP-based 2FA:
- Users enroll via Settings > Account (QR code + backup codes)
- Admins can enforce server-wide 2FA via the `require_2fa` setting in the admin panel
- `require_2fa` requires all users to have 2FA enabled and registration to be closed
- Login flow returns `requires_2fa: true` with a `partial_token` (10-min TTL, 5-attempt limit)
- Auth challenges are rate-limited to 10 req/min per IP
- TOTP code verification uses constant-time comparison (`subtle.ConstantTimeCompare`) to prevent timing side-channel attacks
## Account Deletion
Users can delete their own account via `DELETE /api/v1/auth/account` with password confirmation. The last admin account cannot be deleted. After 3 failed password attempts, the endpoint locks out for 15 minutes.
## Audit Logging
Security-relevant actions are recorded in the `audit_log` table with actor, action, target, and detail:
- **Auth:** `user_register`, `user_login`, `user_logout`, `login_blocked_banned`, `account_deleted`
- **2FA:** `totp_enabled`, `totp_verified`, `totp_disabled`
- **Admin:** `role_change`, `user_ban`, `user_unban`, `force_logout`, `setting_change`, `server_setup`
- **Content:** `channel_create`, `channel_update`, `channel_delete`, `message_delete`
- **Ops:** `backup_create`, `backup_delete`, `backup_restore`, `ws_connect`
## Client Security Hardening
The Tauri desktop client implements the following security measures:
### Credential Storage
- Credentials are stored in Windows Credential Manager via DPAPI (per-user scope, `CRED_PERSIST_ENTERPRISE`)
- Plaintext passwords are **never** returned to the frontend over IPC — only tokens are accessible from JavaScript
- Auto-login uses stored tokens for reconnection, not passwords
### Tauri Capabilities (Least Privilege)
- Filesystem write access is scoped to `$APPDATA/**` and `$APPLOG/**` only
- DevTools command is gated behind the `devtools` feature flag (excluded from release builds)
- HTTP fetch permissions are restricted to `https://` origins
### TLS and Certificate Pinning (TOFU)
- Self-signed certificates are supported via Trust-On-First-Use (TOFU) pinning
- The WebSocket proxy (`ws_proxy`) pins the server certificate fingerprint on first connection
- The LiveKit proxy (`livekit_proxy`) reuses the pinned fingerprint from the WS proxy
- Certificate mismatch triggers a modal requiring user acknowledgment
- Update downloads validate `server_url` uses `https://` and rejects URLs with userinfo
### Input Validation
- IPC commands validate host format, string lengths, and character allowlists
- PTT virtual key codes are validated to the Win32 range (1254)
- LiveKit proxy `remote_host` is validated against CRLF injection
- API client validates host format before constructing URLs
- File uploads enforce a MIME type allowlist (images, video, audio, PDF, text)
- Error messages from server responses are capped at 200 characters
- Notification titles are sanitized (control chars stripped, length capped)
### XSS Prevention
- All user-generated content is rendered via `textContent`/`setText` — never `innerHTML`
- The single `innerHTML` usage (SVG icons) operates on compile-time constants with a runtime guard
- URLs are validated via `isSafeUrl` (rejects `javascript:`, `data:`, `vbscript:`)
- YouTube embeds use `sandbox` attribute on iframes
- `image/svg+xml` is excluded from safe MIME types for data URIs
- Tenor GIF URLs are validated against trusted CDN origins
- Linkified URLs strip trailing punctuation to prevent misleading destinations
### Search and Rate Limiting
- Client-side search requests are rate-limited (500ms minimum interval + 300ms debounce)
## Known Limitations
- No code signing yet -- binaries are verified via SHA256 checksums only
- The Tenor API key is hardcoded (Google's public anonymous key) — consider build-time injection for production
- CSP `connect-src` allows `https:` to any host (necessary for self-hosted server URLs not known at build time)
## Security Hardening Checklist for Operators
- [ ] Enable TLS (self-signed is the default; custom certs recommended for production)
- [ ] Keep invite-only registration enabled (default)
- [ ] Set a strong admin password
- [ ] Configure rate limits (defaults are sensible but review for your use case)
- [ ] Run regular backups via the admin panel
- [ ] Keep the server updated (admin panel shows available updates)
- [ ] Firewall: only expose port 8443 (HTTPS) and 7880 (LiveKit WebSocket for voice/video)
- [ ] Enable server-wide 2FA requirement once all users have enrolled
- [ ] Set `admin_allowed_cidrs` to restrict admin panel access to trusted networks