Transparent security practices, data protection mechanisms, and compliance standards
No Security by Obscurity: We believe that security should not rely on hiding how things work. True security comes from robust design, not secrecy. This page documents everything—our security measures, data handling, compliance practices, and even our vulnerabilities.
Painful Transparency: We are committed to being transparent about everything related to security and privacy. If you find a vulnerability, we want to know. If you have questions, we'll answer them honestly. We're the good guys, and we have nothing to hide.
Privacy by Design: Privacy is not an afterthought. It's built into every layer of our architecture, from database security rules to API authentication to data retention policies.
Data Export: You can export all your personal data at any time via Account Settings.
Export includes: Profile data, all reflections, AIC results, badges, goals, and timestamps. Format: JSON (machine-readable).
API Endpoint: GET /api/account/export
Requires authentication. Returns JSON file with all user data. Server-side authentication ensures you can only export your own data.
Account Deletion: You can permanently delete your account and all data at any time via Account Settings.
Deletion is immediate and irreversible. All data is removed: reflections, AIC results, badges, goals, profile data, and Firebase Auth account. No data retention after deletion.
API Endpoint: POST /api/account/delete
Uses Firestore batch operations for atomic deletion. Server-side authentication ensures you can only delete your own account.
Export Format: JSON (structured, machine-readable)
All data is exported in a standard JSON format that can be imported into other services. Includes complete data structure with timestamps and relationships.
Our privacy policy (/privacy) accurately reflects our data collection and handling practices. We do not collect data beyond what is stated in the policy.
Location: firestore.rules
match /users/{userId}/{document=**} {
allow read, write: if isOwner(userId);
}Users can only access their own data. No cross-user access possible. Enforced at database level.
match /analytics_logs/{logId} {
allow write: if isAuthenticated();
allow read: if false; // Logs are write-only
}Users cannot read analytics/error logs. Prevents data leakage through logs.
match /{document=**} {
allow read, write: if false;
}All collections are denied by default. Explicit allow rules required for any access.
Full Rules File: Available in our repository at firestore.rules. We encourage security researchers to review them.
Server-Side Authentication:
Authorization: Bearer <token> headerResource Ownership:
Known Issue: Some account routes (pause, resume, cancel) were recently updated to use server-side auth. All routes now use proper server-side authentication.
Architecture: Dual Redis instance system with automatic data sharding
Automatic Key Routing: The system automatically routes data to the appropriate Redis instance based on key patterns. Secure keys (subscription:, admin:, token:) always go to Redis Cloud. Public keys (emotion:, cache:) go to Upstash. This ensures user data is never exposed to client-side access.
dev:, stage:, prod:)Implementation: Redis Cloud (secure instance) with in-memory fallback
Rate limits are enforced per user ID. Admin users bypass rate limits. Rate limit headers included in all responses:X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
CRITICAL: Chat messages are NEVER stored, logged, or persisted. They exist only in memory during active sessions and are permanently lost when you close the browser/app or the session ends.
Encryption at Rest: All data in Firestore is encrypted at rest by Google Cloud Platform. This is automatic and requires no configuration.
Encryption in Transit: All connections use HTTPS/TLS. No unencrypted data transmission.
No Local Storage: Sensitive data is not stored in browser localStorage. Auth tokens are managed securely by Firebase Auth.
Environment Variables: All API keys and secrets are stored in environment variables, never in code. Production secrets are in Vercel/Railway, not in the repository.
Google OAuth: Used for authentication. Data shared: Email, name, profile photo (via OAuth consent). User must explicitly consent.
Firebase/Firestore: All user data stored in Firebase. Google Cloud Platform privacy policy applies. Firebase is a data processor, not a data controller.
Google Gemini AI: Used for emotion analysis. Data shared: CVM facts, affect labels, context descriptions. Data NOT used for training (per Google's API terms). User can disable AIC features.
Google Analytics: Usage analytics only. Does NOT track: Personal reflection content, emotion selections (only event type), user-typed text, location data. Anonymized event data only.
Purpose: Payment processing and subscription management
Data shared: Email address (for customer creation), subscription metadata (user ID, plan ID)
Data NOT shared: Credit card numbers, billing addresses, payment history (handled by Stripe)
Security: PCI-DSS compliant. Credit card information never touches our servers.
Datadog: RUM, APM, and Logs. Write-only logs. No personal reflection data in logs.
Sentry: Error tracking. Stack traces sanitized. No sensitive data in error messages.
Vercel Analytics: Web analytics. Anonymized page views only.
Web App: Next.js handles CORS automatically. No explicit CORS configuration needed for same-origin requests.
MCP Server: CORS configured via CORS_ORIGIN environment variable. Production should use specific origins (not *).
Note: Production CORS settings should be verified to restrict origins appropriately.
All API routes validate request bodies using TypeScript types and runtime validation. Invalid data types are rejected. Missing required fields return 400 errors.
File uploads validate file type and size limits. Malicious file uploads are rejected.
Error messages do not expose internal details. Stack traces are not returned to clients. Database errors are sanitized. API keys/secrets are never in error messages.
Sensitive data is not logged. Passwords/tokens are never logged. Minimal user data in logs.
We believe in transparency, including about our weaknesses. Here are areas we're working on:
While we've audited account routes, a comprehensive audit of all 70+ text/image/AIC routes is recommended to ensure consistent authentication patterns.
CORS settings should be verified in production to ensure specific origins are used (not wildcard).
Automated security testing (authentication bypass, input injection, etc.) would strengthen our security posture.
Tests with Firestore emulator would verify rules work as intended.
If you find a security vulnerability, we want to know about it. We're committed to fixing issues quickly and transparently.
Please report vulnerabilities to: [email protected]. We will acknowledge receipt within 48 hours and provide updates on our progress.
We follow responsible disclosure practices. We will credit you (if desired) for any vulnerabilities you report.
We conduct regular security audits and document our findings transparently.
Latest Audit: January 2025
Status: All critical issues fixed. Account routes updated to use server-side authentication.
Documentation: Our detailed security audit reports and API authentication audit checklists are not publicly available, but we're happy to share them with security researchers, privacy advocates, or users who have specific concerns.
Request a Copy: Email us at [email protected] to request a copy of our security audit reports.
Active Data: Reflections, profile data, AIC results, badges, and goals are stored until you delete them or delete your account.
Ephemeral Data: CVM facts, camera media, baseline calculations are discarded immediately after processing. Not stored.
Logs: Analytics, error, and activity logs are retained for system monitoring. They are write-only (users cannot read them) and contain minimal user context. No personal reflection data in logs.
Account Deletion: When you delete your account, ALL data is immediately and permanently removed. No data retention after deletion. No recovery period. Firebase Auth account is also deleted.
Subscription Data: Stripe subscription data is retained per Stripe's policy (for billing purposes). This is standard practice for payment processors.
Client-Side: User authenticates via Google OAuth. Firebase Auth provides ID token.
API Requests: Client sends ID token in Authorization: Bearer <token> header.
Server-Side: API route uses Firebase Admin SDK to verify token. User ID extracted from verified token (not from request parameters).
Authorization: User ID used to verify resource ownership. Users can only access their own data.
Location: apps/web-app/src/app/api/account/helpers/export.ts
Method: Server-side function using Firebase Admin SDK. Queries all user collections: profile, reflections, AIC results, badges, goals.
Format: JSON with pretty printing (2-space indent). Includes exportedAt timestamp.
Security: User can only export their own data. Server-side authentication ensures this.
Location: apps/web-app/src/app/api/account/helpers/delete.ts
Method: Firestore batch operations for atomic deletion. Deletes all subcollections: reflections, AIC results, badges, goals, logs, profile snapshots. Then deletes profile and user document. Finally deletes Firebase Auth account.
Atomicity: All deletions succeed or all fail. No partial deletions.
Security: User can only delete their own account. Server-side authentication ensures this.
While our main codebase is not open source, we believe in transparency about our security practices. This page is our commitment to that transparency.
Security researchers, privacy advocates, and users are welcome to review our security documentation, report vulnerabilities, and ask questions. We're here to be transparent and earn your trust.
Have questions about our security practices? Found something that doesn't look right? We want to hear from you.
Security Issues: [email protected]
Privacy Questions: Contact Us
Privacy Policy: /privacy
Terms of Service: /terms
Last updated: 1/4/2026
This page is updated whenever we make security or privacy changes. We commit to keeping it current and accurate.