Last updated: October 2026 · For institutional partners and IT security reviewers.
FERPA school-official design
No school signed yet
HECVAT 4 (answering)
Many answers No today
TLS + HSTS
TLS 1.2+ · 2-year preload
Hosting providers: Vercel and Supabase each hold SOC 2 Type II reports for their own services. White Coat World does not hold a SOC 2 report.
White Coat World is built to operate under the "school official" exception defined in 34 CFR § 99.31(a)(1)(i)(B), and our Data Processing Agreement is written to establish that designation. To be precise about status: that exception attaches once an institution designates us in a signed written agreement, and no institution has been onboarded yet — so today students share their own records with us directly, under their own consent, rather than a school disclosing records to us. Under either arrangement we access student education records only with a legitimate educational interest, and never sell, rent, or otherwise disclose student PII to third parties for commercial purposes. Your deployment would be the first execution of this designation.
White Coat World shows no advertising today. No advertising networks, tracking pixels, retargeting scripts, or marketing cookies are loaded anywhere in the application, and student browsing behavior and profile data are never sold or shared with advertisers. Section 6 of our Terms of Use promises students at least 30 days’ notice, by email and in the platform, before any advertising could begin. Two disclosures for completeness, neither of them an advertising integration: the public marketing homepage embeds an introductory video via YouTube, which sets Google cookies for visitors to that page; and video lessons in the Extra Terrestrial Tests classroom are hosted on YouTube. The classroom player is click-to-load — a lesson shows a placeholder card and requests nothing at all from Google until a student presses play, at which point it loads through youtube-nocookie.com. You can verify that claim yourself in a browser network panel.
We are answering the Higher Education Community Vendor Assessment Toolkit (HECVAT 4), and many answers are No today; we mark them No rather than rounding them up. Institutional IT security reviewers can contact us for the current answers.
We collect only the information necessary for the advisory and admissions-preparation workflow. Faculty members are granted field-level access scoped to what is relevant for their advisory role: they see the academic record they are advising on, including test scores, because an advisor cannot judge school fit without them. Supervisor contact details from a student's logged experiences are excluded from the faculty view, and faculty access is limited to students who have explicitly consented to share with that institution.
All traffic is encrypted in transit with TLS 1.2 or newer (TLS 1.3 where the browser supports it); older versions are refused. HTTP Strict Transport Security (HSTS) is enforced with a 2-year max-age and includes subdomains, enabling HSTS preloading.
All data is stored in Supabase (PostgreSQL), which provides AES-256 encryption at rest on all database volumes and object storage.
Every API endpoint validates input against strict Zod schemas before any database interaction. All database queries use parameterized statements (no raw string interpolation), preventing SQL injection (OWASP A03). String fields are sanitized against regex allowlists to prevent XSS (OWASP A03/A07).
All responses include: Content-Security-Policy (CSP) with allowlisted sources, X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin, and Permissions-Policy disabling camera, microphone, and geolocation.
Two sign-in methods are supported (NextAuth v5, JWT strategy): Google OAuth 2.0, and email with a password. Google's OAuth sub is hashed into a deterministic UUID before storage, preventing user enumeration attacks. Passwords are never stored in recoverable form — only an Argon2id hash (19 MiB memory cost, 2 iterations) is written to the database, and email addresses must be verified before the first password sign-in. New and changed passwords are checked against the Have I Been Pwned breach corpus using k-anonymity: only the first five characters of the password's SHA-1 digest leave our servers, never the password itself.
Time-based one-time password (TOTP) two-factor authentication is available to every account type — student, faculty, school, organization, and administrator — from the account Security tab, and works with any standard authenticator app. The code is asked for when signing in with an email address and password. Google sign-ins rely on Google's own two-step verification instead, which a university's Google Workspace can require for its domain. TOTP secrets are encrypted at rest with AES-256-GCM under a key held outside the database, and each code is single-use (a replay guard rejects a time step that has already been consumed). Ten single-use recovery codes are issued at enrollment and stored only as keyed HMAC-SHA-256 hashes, under a key held outside the database.
All credential tables — password hashes, TOTP secrets, recovery-code hashes, email-verification and password-reset tokens, and one-time-code records — have Row-Level Security enabled with no policies granted to the anon or authenticated roles, making them unreadable by any client-side connection and reachable only by the server's service role. Verification and reset tokens are stored as SHA-256 hashes with short expiry windows (24 hours and 1 hour respectively); the plaintext token exists only in the emailed link.
All uploaded files are validated against their magic bytes (not just MIME headers) using the file-type library, capped at 10 MB, and kept in private storage. The file itself is stored as uploaded; text extracted from it is scrubbed of personal details before it is sent to the AI, as described below. Allowed types: PDF, JPEG, PNG, WebP.
Students explicitly opt into data sharing with their institution before any faculty member can access their profile. Consent is institution-scoped, immediately revocable at any time, and preserves a soft-deleted audit trail so revocation history is never lost.
Students may request permanent deletion of all their data at any time. The erasure endpoint hard-deletes their records across every table in FK-safe order, writes an anonymized audit entry, then terminates the session. No soft-delete fallback — erasure is permanent. Three narrow categories are excluded by design, each described under What Survives Erasure below: the account-closure audit entry, monthly group summaries (counts and averages for groups of 10 or more students, with no names or account IDs), and the record that an agreement was accepted, whose identifiers are erased while the acceptance itself is retained. Stats you share on the Contribute page are stored without your name, under a coded version of your account ID, and are deleted with your account. Our encrypted database backups normally keep a copy for up to 28 days before it ages out; we never restore a backup to bring back a deleted account.
Sensitive operations are recorded in an append-only audit_log table: faculty views of student profiles, consent grants and revocations, admin approvals of faculty accounts, and account deletions. The application cannot edit or delete entries (the database enforces this); entries are kept for 12 months and readable only by platform administrators.
Non-erasure deletions (reports, experiences, etc.) use a soft-delete pattern (deleted_at timestamp). Our application hides soft-deleted rows; row-level security does not do this, because our server reads the database with a service key that bypasses it. Soft-deleted rows are permanently removed after 30 days (see Automated Purge).
Faculty at Institution A cannot access students from Institution B. Isolation is enforced server-side at the API layer — every request is authenticated and scoped to the caller's institution and consent grants — with Postgres Row-Level Security as an additional defense-in-depth layer.
White Coat World is deployed on Vercel, which holds SOC 2 Type II and ISO 27001 certifications. All environment secrets are stored in Vercel's encrypted secret vault — no credentials are committed to source code.
Our PostgreSQL database and object storage are hosted on Supabase, which holds SOC 2 Type II certification. Our Supabase plan includes no backups, so we make our own: see Backblaze and GitHub below.
Normally every night, a backup job copies the database, encrypts it with keys we hold offline, and stores it in Backblaze B2 in the United States, so Backblaze holds only data it cannot read (paused from October 19 to November 1, 2026, while our build service was unavailable). We keep 7 daily and 4 weekly copies, so a deleted record can normally remain inside an encrypted backup for up to 28 days (longer in Backblaze when nightly backups are not running, because older Backblaze copies are removed only after a new one succeeds). Backups cover the database, not uploaded files, and are not point-in-time recovery: a restore returns the database to the previous night. Each night the job checks that the copy restores into a temporary database, but we have not yet practised a full recovery from one, so we do not yet rely on these backups.
The backup job runs on GitHub Actions (paused from October 19 to November 1, 2026). For a few minutes each night, GitHub's temporary build machine holds the unencrypted database while it makes and checks the backup, and the machine is deleted when the job ends. GitHub also keeps a second encrypted copy of each backup for 7 days and then deletes it automatically, including while backups are paused.
AI gap analysis and writing coaching are powered by Google Gemini Flash. Every piece of student text is scrubbed before it reaches the model, at one of two strengths. Uploaded transcripts have contact details and the student's name redacted, because a name is noise in a document we are parsing for courses and dates. Text the student types — personal statements, experience descriptions and interview answers — has Social Security numbers, email addresses, phone numbers and ID numbers redacted, while proper nouns are deliberately preserved: an essay stripped of "Mayo Clinic" and the mentor who taught them cannot be coached. Each feature also caps how much text it sends; the largest is an uploaded transcript, at up to 40,000 characters, and a personal-statement draft is capped at 6,000. We do not use student data to train or fine-tune models, and we use Google's paid Gemini API, under whose terms Google does not use what we send to improve its products and keeps it for up to 55 days, only to detect abuse.
Built so that an institution that requires it can have its students' AI requests processed by Microsoft Azure OpenAI instead of Google. It is not active today: no institution has selected it, so no data is sent to Microsoft. We list it so you know before it is ever turned on.
When a student connects White Coat World to ChatGPT, the data the student chooses to share, limited to the permissions they approve, is returned to their ChatGPT session and handled under the terms of their ChatGPT account or workspace. This connection is in early access: today it is live only for the founder's own account, and other students can connect only by joining through the early-access step.
Transactional email is implemented against Resend and sends from a verified sending domain we control, whitecoatworld.org, with SPF and DKIM published for it. Flows that email a third party — faculty .edu verification, invitations, supervisor hour-verification requests, and survey and review reminders — are available. Each of them still checks the configured sender before doing anything and returns an explicit operator error rather than attempting a delivery that would fail, so a misconfiguration surfaces as a refusal instead of as silence. No student PII appears in an email body beyond first name and the specific section a review was requested for, and account emails (verification and password reset) carry a single-use, short-lived token.
Upstash Redis holds rate-limit counters and short-lived caches: session and sign-in status checks, recent feed-recommendation signals, and a copy of a generated AI report for up to one hour. Keys are derived from IP addresses, user IDs, and — for the one-time-code limiter — phone numbers. Uploaded files are never stored there, every entry expires automatically, and deleting an account clears its cached reports at once.
SMS delivery of one-time codes is implemented against Twilio. It is not active in the current configuration: no Twilio credentials are provisioned, so no SMS is sent and no phone number is transmitted to Twilio today. We list it because enabling SMS delivery would engage Twilio as a sub-processor, and institutions should evaluate it as part of the review rather than be surprised by it later.
Application error reporting is sent to Sentry with personally identifiable information collection disabled. Every report is scrubbed before it is sent: request bodies, query strings, cookies, headers, console logs and database values are removed.
Server-side product analytics — which features are used and how often — keyed to a pseudonymous account identifier, never a name or email. It records product events, not student academic content: no transcript, GPA, personal statement, experience, or advising material is sent to PostHog. Listed here so that this page, the Privacy Policy and the Data Processing Agreement name exactly the same set of sub-processors.
When a password is created or changed, we check it against the Have I Been Pwned breach corpus using the k-anonymity range API. Only the first five characters of the password's SHA-1 digest are transmitted; the password, the full digest, and the user's identity are never sent, and the service cannot determine which password was checked.
Resend delivers our transactional email through Amazon SES (us-east-1). SES therefore receives the recipient address and message content of verification, password-reset, and notification emails.
The optional location field in the social layer geocodes the text a user types through OpenStreetMap Nominatim, from their browser. It is not part of the academic profile or advising workflow.
Looking up a supervising provider sends the entered search terms to the public CMS NPI Registry. No account identifier is included.
The optional location field in the social layer uses Google Places for autocomplete, which sends the text a user types in that field to Google from their browser. It is used only for that field and is not part of the academic profile or advising workflow.
YouTube appears in two places. On the public marketing homepage an introductory video is embedded directly, so it loads for anonymous visitors before any account exists and sets Google cookies for that page. In the Extra Terrestrial Tests classroom, video lessons are hosted on YouTube and played through youtube-nocookie.com — but the player is click-to-load: until a student presses play on a specific lesson, the page contains no YouTube iframe, no YouTube script, and not even a thumbnail, so nothing whatsoever is requested from Google. That is deliberate and it is verifiable: open a chapter page with the network panel filtered to google, youtube, ytimg or googlevideo and it stays empty until you click. Neither embed is an advertising or tracking integration, and no student record, answer, or score is ever transmitted to YouTube — the only thing sent when a student presses play is the video ID they chose to watch. The one other in-browser third party anywhere in the product is the Google Places autocomplete described above, which runs on a signed-in page but only for the optional location field.
Academic profiles, experiences, reports, and uploaded documents are retained until the student permanently deletes their account. Soft-deleted records (e.g., removed experiences) are permanently removed after 30 days. Audit log entries are retained for 12 months then automatically rolled off. Legal acceptance records — which agreement, which version, when, and a digest of the published text — are retained after deletion with the signer's identifiers erased. Stats you share on the Contribute page are stored without your name, under a coded version of your account ID, and are deleted with your account. The full schedule is in the Privacy Policy.
Students may trigger a permanent, irreversible hard delete of all their data directly from Settings → Privacy. The erasure endpoint deletes their records across every table in FK-safe order, writes one final audit log entry before deletion, and terminates the session. No soft-delete fallback — data is gone from our own databases immediately, subject only to the three exclusions and the backup window described below. Our product analytics provider holds only a pseudonymous identifier and usage events; the cascade asks it to erase them, which it does in a weekly batch, within about a week.
Three things outlive an account. The account-closure audit entry (an identifier and a timestamp) rolls off after 12 months. Monthly group summaries (counts and averages by institution, program and class year) are kept; since October 2026 none is ever stored for a group under 10 students, and they hold no names or account IDs. And the record that the account accepted a given agreement is retained — the IP address and browser details are erased, but the acceptance itself is kept as proof that an agreement whose indemnity and dispute-resolution terms survive termination was in fact formed. That record is append-only and cannot be edited or deleted, including by us: it is enforced by a database trigger rather than by permissions, because our own service credentials bypass row-level security. Stats you share on the Contribute page are not among them: they are stored without your name, under a coded version of your account ID, and are deleted with your account. Only White Coat World's administrator sees the combined numbers, and groups under 5 are hidden.
Deleted records are removed from the Supabase PostgreSQL database and object storage (Supabase Storage). Supabase performs secure data disposal at the infrastructure layer in compliance with their SOC 2 Type II controls. Copies inside our encrypted database backups are deleted as those backups age out, normally within 28 days.
A scheduled job runs nightly to permanently delete database records that have been soft-deleted for more than 30 days. It covers most kinds of student record, including experiences, reports, target schools, posts and comments; anything it does not yet cover is removed when the account is deleted. Uploaded files are handled separately: when a student removes one, the file is deleted from storage at the same time, and a daily job retries any removal that fails.
Users sign in through their institution’s identity provider where one is configured, or with Google OAuth 2.0 or an email address and password (NextAuth v5, JWT strategy). Google sign-ins use Google’s own two-step protection (which a university’s Google Workspace can require); email-and-password accounts can add a White Coat World two-step code. See section 2 for how credentials are hashed, encrypted, and isolated.
Generic OIDC federation is implemented and driven entirely by configuration — no code change or deploy is required to onboard an institution, and multiple institutions can be federated at once, each with its own isolated identity namespace. Any OIDC-compliant identity provider works, including Microsoft Entra ID (Azure AD), Okta, Google Workspace for Education, and Shibboleth deployments fronted by an OIDC bridge. Enabling it means supplying a provider identifier, display name, issuer URL, client ID, and client secret; the client secret is encrypted at rest with AES-256-GCM under a key held outside the database, so a database-only compromise does not yield it. Native SAML 2.0 is not supported — see the note below. Being precise about status: no institution has been onboarded yet, and this path has not yet completed an end-to-end login against a live identity provider, so your deployment would be the first exercise of it rather than a change to an existing one.
Automatic email-based account linking is deliberately disabled. A user who already holds a personal Google account under the same email address is never silently merged into the institutional identity — the two remain distinct until deliberately reconciled. This prevents an institutional SSO deployment from retroactively absorbing accounts your institution does not control.
We do not support native SAML 2.0. Institutions standardized on SAML typically federate through an OIDC bridge at their identity provider, which the integration above supports. If native SAML is a hard requirement for your review, contact us so we can scope it honestly rather than list it as available.
The platform enforces distinct roles stored in the user_roles table — including Student, Faculty, Admin, and several institutional/organizational roles for schools, healthcare organizations, and pre-health programs. Each role's access is enforced server-side on every API request, with database Row-Level Security policies as defense-in-depth. Administrator is never self-assignable. The remaining roles are self-declared when an account is created, and declaring one confers no access to anyone else's data on its own: a faculty account reaches a student's record only after its institutional email address is verified, the account is approved by us, and the student has separately granted consent; institutional and organizational accounts require our verification on the same basis. Switching an existing account to a different role is refused. We are moving the institutional roles to explicit provisioning ahead of our first institutional deployment.
Sessions use HttpOnly, Secure, SameSite=Lax cookies. JWT sessions expire after 7 days, with the token refreshed at most once every 24 hours of activity. Because JWT sessions are stateless, we implement server-side revocation through a per-user session version stamped into each token and re-validated periodically: incrementing it invalidates every outstanding session for that user on every device. It is incremented on password reset, on disabling two-factor authentication, and when a user presses "Sign out of all devices" on their Security tab. Deleting an account ends every session that began before the deletion in the same way. Revocation propagates within 5 minutes rather than instantly — the version is cached to keep the re-check off the database on every request, and that cache window is the latency. The check deliberately fails open on an infrastructure error, so a cache or database outage degrades to "no revocation this cycle" rather than signing out the entire userbase. We do not currently enforce a per-user concurrent-session cap.
If you discover a security vulnerability in White Coat World, please report it through our contact form before public disclosure, choosing "Legal notice" as the subject. Reports filed there raise an alert immediately, and for those we commit to: acknowledging your report within 48 hours, providing a status update within 7 days, and crediting reporters who follow responsible disclosure practices.
Security reports: https://whitecoatworld.org/contact — choose "Legal notice" as the subject, and include a description of the vulnerability, steps to reproduce, your assessment of impact, and an address we can reply to. We also publish security@whitecoatworld.org for reviewers whose process requires an address on file; inbound delivery to it is still being provisioned, so until that is live the form is the channel the commitment above attaches to. We do not pursue legal action against good-faith researchers.
If you represent a university Technology Transfer, IT Security, or Compliance office and need our current HECVAT 4 answers, a Data Processing Agreement (DPA), or a security review call, please use our contact form. We also publish security@whitecoatworld.org for review processes that require an address on file, though inbound delivery to it is still being provisioned.