Security Overview
1. Our Security Posture
Lattice stores sensitive information — resumes, application materials, university affiliations, and professional communications. We take this responsibility seriously and apply security best practices appropriate for a production SaaS platform.
This page documents the technical security controls in place. We believe in transparency about our security practices so that students and faculty can make an informed decision about trusting us with their data.
2. Encryption
In transit
- All communication between your browser and Lattice servers is encrypted via TLS 1.2+ (HTTPS).
- HTTP requests are redirected to HTTPS automatically. HTTP Strict Transport Security (HSTS) is enforced.
- API requests between our application and the database are encrypted in transit.
At rest
- Our production database (Neon PostgreSQL) encrypts all data at rest using AES-256.
- Uploaded files (resumes, avatars) are stored on isolated server paths. Production deployments should use encrypted object storage (S3, Cloudflare R2, or Vercel Blob).
- Passwords are never stored — only bcrypt hashes (cost factor 12) are stored. It is computationally infeasible to reverse a bcrypt hash to a plaintext password.
3. Authentication Security
- Password hashing: bcrypt with cost factor 12 via the
bcryptnpm package. - Session tokens: Signed JWTs stored in HttpOnly, Secure, SameSite=Lax cookies. Not accessible to JavaScript on the page.
- Session expiry: Sessions expire after 7 days of inactivity. Signing out immediately invalidates the session.
- Email verification: All new accounts require email verification via a 6-digit OTP before accessing the platform.
- University domain enforcement: Students and professors must use a verified
.eduemail address matching our university registry. - CSRF protection: All state-changing requests include CSRF token validation via NextAuth's built-in CSRF handling.
- OTP security: Email OTPs expire after 15 minutes. After 3 failed attempts, the OTP is invalidated and must be resent.
4. Rate Limiting
All sensitive endpoints are rate-limited to prevent brute-force attacks and abuse:
| Action | Limit |
|---|---|
| Login attempts | 5 per IP per 15 minutes |
| Account registration | 10 per IP per hour |
| Post creation | 10 per user per hour |
| Application submission | 20 per user per day (burst), 25 per week (free tier) |
| OTP resend | 1 per user per 2 minutes |
| Username change | 1 per 30 days (tracked via audit log) |
Rate limits are enforced in-memory per server instance. In production, we recommend Upstash Redis for distributed rate limiting.
5. File Upload Security
- File uploads are validated server-side for MIME type (JPEG, PNG, WebP, GIF for avatars; PDF for resumes).
- Maximum file size: 3 MB for all uploads.
- Files are stored with random, non-guessable paths. Direct enumeration of other users' files is not possible.
- Uploaded files are not executable — they are stored as static files and served with appropriate Content-Type headers.
- In production, file uploads should be moved to an object storage service (S3, Vercel Blob, Cloudflare R2) with private buckets and signed URL access.
6. AI Integration Security
Lattice uses the Anthropic Claude API to optionally screen applications across all post types. AI screening is opt-in per post by the poster. The following controls are in place to protect applicant data and prevent misuse.
API key isolation
- The Anthropic API key is stored exclusively in server-side environment variables. It is never included in client-side bundles and is not prefixed with
NEXT_PUBLIC_. - The AI screening module contains a runtime guard that throws an error if it is ever executed in a browser context.
- There is no public API endpoint for AI screening — it is invoked server-side only after a verified application submission.
Access control
- AI screening only triggers when: (1) the post author has enabled it on that specific post, and (2) the author has remaining monthly quota.
- Authentication is required (valid session + STUDENT role + verified email) before any application can be submitted.
- AI scores are written directly to the database from the server — they cannot be submitted or manipulated by the applicant.
- AI scores are returned only through authenticated poster/admin API responses and are never included in applicant-facing API responses.
Monthly quota limits
- Each poster has a monthly AI screening quota based on their subscription plan (5–15 for professors, 2–6 for students, 3–9 for teams).
- Per-post API rate limit: 50 requests/hour — prevents a single high-traffic post from exhausting the quota.
- Global API rate limit: 300 requests/hour — hard cap on total Anthropic API spend.
- When any limit is hit, the application still submits successfully and lands in an "Unscreened" tier for the poster to review manually.
Data minimization in transit
- Only the minimum fields required for scoring are sent: written responses, truncated resume text (max 3,000 characters), major, skills, and GPA (only if the applicant has enabled "Show GPA").
- Applicant name, email, university, contact details, and social links are never sent to the AI model.
- All API calls to Anthropic are made over TLS.
7. Responsible Disclosure
If you discover a security vulnerability in Lattice, please report it to us responsibly before disclosing it publicly. We appreciate the security community's help in keeping our platform safe.
Email: security@joinlattice.app
Please include in your report:
- A description of the vulnerability and its potential impact
- Steps to reproduce the issue
- Any relevant screenshots, logs, or proof-of-concept (do not exfiltrate real user data)
Our commitment to you:
- We will acknowledge your report within 3 business days
- We will investigate and provide an update within 10 business days
- We will not pursue legal action against researchers acting in good faith
- We will credit you in our changelog if you wish, once the vulnerability is resolved
A formal bug bounty program is planned for a future launch date. Stay tuned.
8. Contact
For security-related inquiries: security@joinlattice.app
For general privacy concerns: privacy@joinlattice.app