Trust Updated 2026-09-11 View as Markdown

Security and privacy

This page describes the security contract: what is protected, how, and what is not. It does not describe internal defensive heuristics, which would be counterproductive to publish.

Accounts

Passwords are hashed with bcrypt at 12 rounds and compared in a timing-safe way. Only the hash is stored; the plaintext is never written anywhere.

Sessions use signed tokens with a bounded lifetime. Change your password or use Sign out other devices in Settings and every other session dies on the next request — and so does every API token and every connected MCP client, including the OAuth grants behind them. Reconnect the clients you still want afterwards. Sessions are still not used as machine credentials: /api/mcp accepts only an API token. See authentication.

Encryption

A specific set of profile fields is encrypted at rest with AES-256-GCM under a per-value random initialization vector, so identical inputs do not produce identical ciphertext. Your WHOOP access and refresh tokens are encrypted the same way.

21 profile fields are encrypted at rest. This list is generated from the field policy the code enforces, so it cannot drift from what is actually sealed.

Encrypted field Why
additional Unbounded free text; may contain anything, so cleared for nothing.
age Personal attribute; identifying in combination.
allergies Health disclosure.
city Location is identifying in combination with the rest of the record.
customCommitment Verbatim personal commitment.
displayName The one field that turns a de-identified medical record into an identified one.
goal Free text about what the person wants for their body.
goalWeight Health goal.
height Personal attribute; identifying in combination.
injuries Health disclosure.
missionCommitment1 Verbatim personal commitment.
missionCommitment2 Verbatim personal commitment.
missionCommitment3 Verbatim personal commitment.
missionCoreGoal Verbatim personal statement.
missionDeadline Part of the Mission Statement; sealed with it.
missionOutcome Verbatim personal statement.
missionStartDate Part of the Mission Statement; sealed with it.
state Location is identifying in combination with the rest of the record.
whatFailedBefore Free-text personal history.
whatWorkedBefore Free-text personal history.
zipCode Location is identifying in combination with the rest of the record.

The remaining 54 profile fields — coaching-style preferences, enums and flags such as afterSlipup, alcohol, alcoholFrequency — are stored in the clear. A profile field the policy does not name is treated as sensitive by default.

Nothing else is. In plain terms:

Stored in the clear
Lab results Every marker and value from an uploaded bloodwork report
Methylation results Your genotypes
Coach conversations The full transcript of every chat
Progress pictures The image data itself
Ledger data Push-ups, meals, weights, habit checkboxes
Daily summaries and learnings Generated prose about your patterns
Your username

The database itself is encrypted at rest by the provider, and access to it is limited. Application-layer encryption — the kind that survives a database compromise — covers the fields listed above and your wearable tokens, and nothing more. If you are uploading a genome or a bloodwork panel, assume it is protected by database access control rather than by field-level cryptography.

Reads fail closed: a value that cannot be decrypted is withheld rather than served as raw ciphertext.

Machine credentials

API tokens for the MCP server are stored only as SHA-256 hashes, carry explicit non-cumulative scopes, and are checked against the database on every call — so revocation takes effect on the very next request. Full detail in authentication.

The MCP endpoint additionally refuses any request carrying a browser Origin header, which is what the MCP transport specification asks for to close the DNS-rebinding case.

AI safety

Prompt injection defense. Input to the AI endpoints is screened before it reaches a model, and suspicious content is either sanitized or blocked. This matters more here than in a typical chat product because the coach reads text you did not necessarily write — imported CSV content, extracted lab-report text, meal notes.

Length and history bounds. Message length, conversation depth and total conversation size are all capped, so a single request cannot exhaust the context window.

Your data is not training data. Content sent to model providers is processed to answer your request. It is not used to train models, and it is not shared with anyone else.

Third parties

Service Receives Why
MongoDB Atlas Everything, as the system of record Storage
xAI Coaching context for the current request; lab and methylation text during extraction Chat, voice, extraction
VoyageAI Day and summary text Embeddings and reranking
WHOOP Nothing. Data flows inbound only Wearable sync
Vercel Request metadata and logs Hosting

Two things deliberately never leave your device or your account:

  • Lab and methylation PDFs. Text extraction happens in your browser. Only the extracted text is sent for parsing, so the file — with its name, date of birth and provider header — stays local.
  • Progress pictures. Stored against your account and returned only to you. Not sent to any model, not embedded, and not readable by any MCP tool. Stored unencrypted; see the table above.

Infrastructure

HTTPS everywhere, enforced by the platform. The two libraries loaded from a CDN at runtime (Chart.js and the PDF reader) are pinned to an exact version and a subresource-integrity hash, so a modified file is refused by the browser before it runs. Rate limits per user and per action. Circuit breakers that fail fast when an upstream service degrades rather than hanging your request. Schema validation on every API request, including sanitization that rejects MongoDB operators in field names. Structured logging with semantic event names, which is what makes an anomaly visible.

What is not protected

Being straight about the limits is more useful than a longer list of controls.

Rate limits are not a hard quota. They are sized to bound abuse rather than to meter usage precisely, so treat a published limit as the intended ceiling rather than a guarantee.

API tokens do not expire. That is safe only because revocation is immediate. A token you have forgotten about is a token that still works — list them periodically and revoke what you no longer use.

Health documents are not field-level encrypted. Lab results, methylation results, progress pictures and chat transcripts sit in the clear inside the database. See the table above.

Ledger data is readable by anyone with database access. See the encryption section above. The set of people with that access is very small, but it is not zero.

This is early-access software. It is built carefully and tested, but it has not been through an external security audit.

Your data

Export. CSV export of your full ledger over any range, at any time, without asking anyone.

Deletion. Delete the account from Settings (username + password). The record and every user-scoped collection go with it.

Ownership. It is your data. It is not sold, not shared with advertisers, and not used to train anything.

Reporting a problem

If you find a security issue, report it privately rather than publicly, and give a reasonable window for a fix before disclosure. Write to Austin@nLight.fit.