Security at MyNotes
What we do to keep your notes private, what we don't claim to do, and how to reach us if you find a problem.
Encryption
- In transit. Every page and API request is HTTPS-only with HSTS. Plain-HTTP requests are upgraded automatically.
- At rest. The PostgreSQL database and its backups are encrypted by the managed-Postgres provider. Backup snapshots are encrypted independently and rotated.
- Not end-to-end encrypted. Honest framing: notes are not encrypted client-side, which means an operator with database access could in principle read them — the same as for almost any hosted note-taking service. Our Terms commit us not to.
Authentication & sessions
- Password requirements. Minimum length and complexity (one uppercase, one lowercase, one digit, one special character) are enforced at sign-up and password change.
- Email confirmation required. Accounts cannot sign in until the email has been confirmed.
- Disposable-email blocklist. Sign-ups from temporary-email providers are rejected.
- Session rotation. Changing your password rotates the per-user session token — every previously-signed-in browser is signed out on its next request. Manual "sign out all other devices" is also available from
/settings/security. - Brute-force protection.
Rack::Attackthrottles sign-ups (5 / hour / IP) and per-email login attempts (5 / 20 minutes) — blunting credential-stuffing without locking real users out. - Two-factor authentication. Not yet — on the short list. In the meantime, use a unique strong password from a password manager.
Authorization
- Implicit per-user scoping. Every authenticated read goes through
current_user.notes.find— there are noNote.find(id)call paths in the controller layer. A request for someone else's note id returns 404, not "forbidden." - CSRF protection. All state-changing browser requests carry a per-session CSRF token; the API uses bearer-token auth and is exempt from cookie-based CSRF (a stolen cookie can't make API calls).
- Scoped error logs. The per-user API error log is read through
current_user.api_errorsonly — there's no admin route that exposes another user's request paths.
API tokens
- Stored hashed. Tokens are hashed at rest; the plaintext is shown to the user once at issuance and never recovered.
- Default 90-day expiry. Tokens issued without an explicit expiry are capped at 90 days. User-set expiries beyond one year are rejected. Past expiries are rejected outright.
- Per-token rate limits. Reads / writes / appends per minute are capped per-tier — see /limits.
- Idempotency keys on every write endpoint with a 24-hour dedup window per user — replays with a different body return
409 idempotency_key_conflict. - Revocable from the UI. /settings/api_tokens shows every active token; revoke flips it dead instantly.
Dependencies & infrastructure
- Continuous dependency scanning. Every push runs
bundler-audit(Ruby gems) andimportmap audit(JS modules) in CI. A known-vulnerable dependency fails the build. - Static analysis on every push.
brakemanscans the Rails source for the OWASP-derived issue classes; a finding fails the build. - Error tracking. Sentry captures unhandled exceptions in production; Personally-identifiable data is scrubbed at the SDK boundary.
- Encrypted backups. Daily Postgres dumps are pruned on a retention schedule and copied off-host (rsync / S3-compatible).
Privacy posture
Operational specifics are in the Privacy Policy. Two commitments worth surfacing here:
- No AI training on your notes. Bound by the Terms.
- Reading and exporting are free even after a subscription lapses. Your notes are never inaccessible to you.
Reporting a vulnerability
Found a security issue? Email hello@example.com with SECURITY in the subject line. We'll acknowledge within one business day and keep you in the loop while we patch. Please don't publicly disclose until we've had a reasonable chance to fix the issue.
The machine-readable companion to this section lives at /.well-known/security.txt (RFC 9116).