← Explica

# Explica Security

Two audiences: what to tell a school's IT department, and what you still need to fix before you can honestly answer their questionnaire.

---

## What's built

**Authentication**
- Sign-in is Google OAuth only. Explica never sees or stores a password.
- Sessions are signed JWTs (30-day expiry) held in `chrome.storage` (extension) or `localStorage` (dashboard).
- API keys live server-side only. Students never hold an Anthropic key.

**Authorization**
- Every `/api/*` route requires a valid session.
- Teachers can only read rosters, submissions, and analytics for classes they own — checked per request against `teacher_id`, not trusted from the client.
- School admins are scoped to their own organization.
- Platform ownership comes from the `OWNER_EMAILS` environment variable, not the database, so it can't be granted through the app and survives a database restore.

**Domain claiming**
Claiming an email domain would otherwise let one person absorb everyone at a school. Three controls:
1. Your sign-in address must be at the domain you're claiming.
2. Public email providers (gmail.com, outlook.com, …) can never be claimed.
3. **A claim grants nothing until verified** by a DNS TXT record — which only whoever controls the domain's DNS can publish — or by manual approval from the platform owner.

**Student accounts**
- A student's lookup history, saved words, and progress are readable only by that
  student. Teachers see class activity through the class they own, never another
  teacher's class and never a student's private practice writing.
- Assignments are done in the web app, so a device that cannot install browser
  extensions can still complete coursework. The extension adds explanations on
  other websites; it is not required for anything a teacher sets.

**Data handling**
- Private practice writing is never sent to the server.
- Paste detection records the size, count, and text of large pastes (25+ characters
  at once) made into an assignment editor. The pasted text is stored so a teacher can
  see what was pasted rather than only that a paste occurred, and is shown only to the
  teacher who owns that class. It is captured **only** inside the Explica assignment
  editor — never from other pages, other applications, or the clipboard generally, and
  only when a student is actively pasting into their own assignment.
- Paste records are deleted alongside the submission they belong to, and are covered by
  the same retention window.
- Uploaded reading PDFs are stored on disk under a random name, never under the
  uploaded filename, and are served only to members of the class the assignment
  belongs to. Every upload is parsed and validated as a PDF before it is stored;
  files are capped at 25 MB and parsing runs with script evaluation and external
  resource fetching disabled.
- Reading activity records active time, per-page time, and lookup counts. It does
  not record keystrokes, screen contents, camera, or any activity outside the
  Explica reading tab.
- Deleting a class removes its assignments, submissions, reading activity, and
  uploaded PDFs in one transaction, including the files on disk.

---

## Known gaps — fix before selling

These are real. Don't answer a security questionnaire without addressing them.

| Gap | Risk | Fix |
|---|---|---|
| **No audit log** | Can't answer "who expired this school?" or "who read this student's work?" | Append-only log of admin and owner actions |
| **No rate limiting** | A stolen token could run up an unbounded Anthropic bill | Per-user and per-org request caps |
| **Access isn't enforced in the extension** | `/api/access` returns the right answer but nothing consumes it, so an uncovered user can still use the product | Gate lookups on entitlement |
| **Tokens can't be revoked** | A 30-day JWT stays valid after sign-out or after a student leaves | Server-side session table, or short tokens plus refresh |
| **SQLite, single file** | Fine at this scale; no automatic backup, and a lost volume is a lost customer | Scheduled backups; Postgres when you outgrow it |
| **No 2FA on owner access** | Owner email compromise = every customer's data | Rely on Google 2FA and require it for owner accounts |
| **Secrets in `.env`** | Fine locally; on the host they're only as safe as the dashboard login | Use the host's secret manager; rotate the Anthropic key if exposed |
| **No penetration test** | Districts increasingly ask | Budget for one before a large deployment |

---

## Operational practice

- `server/.env` and `server/data/` are git-ignored. **Never commit real keys.** If one leaks, rotate it at console.anthropic.com immediately — assume anything committed to git is public forever.
- Rotate `JWT_SECRET` only when necessary: it signs every session out.
- Keep `OWNER_EMAILS` to the minimum set of people, on accounts with 2FA.
- Back up the SQLite volume before deploys and migrations.

## Reporting a vulnerability

Email [security@yourdomain]. We aim to acknowledge within [2 business days]. Please don't disclose publicly until it's fixed.