Security
How GrantAmp protects research data.
Flows, encryption, access controls, and how to reach the security contact.
Last updated 2026-10-03.
What this page covers
This page describes how GrantAmp handles unpublished research data, who can reach it, and how to report a security issue. It is written from the code and the data inventory, and it changes when those change.
Data flows
GrantAmp separates ephemeral checks from stored companion data. The free checker, workspace PDF uploads, reference check, and pre-flight read a PDF once in memory and discard it. Ask and the reviewer lens send only what each feature needs to Voyage AI and Anthropic, as the privacy page states.
The table on the /subprocessors page lists every processor. The data inventory below matches docs/trust/data-inventory.yaml and lists each feature, what leaves the browser, where it is stored, for how long, and how it is deleted.
Data inventory
Each row below matches docs/trust/data-inventory.yaml: feature, what leaves the browser, processor, storage, retention, and deletion.
- Free PDF checker. Leaves the browser: The PDF bytes for one check. Processor: GrantAmp container on Cloudflare (in memory only). Storage: None. The file is not written to disk or D1. Retention: Discarded when the response is sent. Deletion: Not applicable.
- Ask. Leaves the browser: The question text once per question. Processor: Voyage AI, then Anthropic, through API access. Storage: None on GrantAmp. Retention: GrantAmp keeps nothing. Processors may hold a request briefly under their abuse policies. Deletion: Not applicable on GrantAmp.
- Sign in and account row. Leaves the browser: Email and profile fields Clerk needs for sign in. Processor: Clerk for authentication; GrantAmp D1 for the users row. Storage: Clerk holds the account. GrantAmp D1 holds user id, email, created_at, terms_version, terms_accepted_at. Retention: Until the person deletes the Clerk account or GrantAmp deletes the row with Delete my data. Deletion: Delete my data removes GrantAmp rows. Clerk account deletion is separate in the user menu.
- Applications, intake, and manifest. Leaves the browser: Application title and intake answers (no science text). Processor: GrantAmp D1 at the edge. Storage: applications and intake_answers tables keyed by user_id. Retention: Until Delete my data or application delete. Deletion: Delete my data or deleting the application.
- Saved workspace drafts. Leaves the browser: Draft text when you press Save draft. Processor: GrantAmp Worker encrypts, GrantAmp D1 stores ciphertext. Storage: drafts and draft_keys tables. AES-GCM with a per person data key wrapped under the DRAFT_KEY secret. Retention: Until you delete the draft, the application, or Delete my data. Deletion: Draft delete, application delete, or Delete my data (draft_keys row makes ciphertext unreadable).
- SciENcv checklist labels and ticks. Leaves the browser: Labels you type and checkbox state. Processor: GrantAmp D1. Storage: scienv_people and scienv_checks tables. Retention: Until Delete my data or application delete. Deletion: Delete my data or application delete.
- AI-use log and attestation PDF. Leaves the browser: Log fields and optional prompts you choose to record. Processor: GrantAmp D1. Prompts encrypted like drafts. Storage: ai_use_log table. Attestation PDF is built on download and not stored. Retention: Until Delete my data or application delete. Deletion: Delete my data or application delete.
- Pre-flight assembled PDF check. Leaves the browser: The assembled PDF once per run. Processor: GrantAmp container in memory, then GrantAmp D1 for the report. Storage: preflight_runs holds counts and findings, not the PDF. Retention: Last report per application until Delete my data or application delete. Deletion: Delete my data or application delete.
- Readiness dashboard ticks. Leaves the browser: Submission checklist ticks. Processor: GrantAmp D1 in submission_checks. Storage: submission_checks table. Retention: Until Delete my data or application delete. Deletion: Delete my data or application delete.
- Reference check. Leaves the browser: DOI, PMID, PMCID, or title and first author per reference. Processor: CrossRef and NCBI public APIs; GrantAmp D1 cache. Storage: citation_records keyed by identifier only, no user_id. Retention: Cache up to ninety days for found records; shorter for not found (see code). Deletion: Daily cron removes expired cache rows. Not tied to a person.
- Reviewer lens. Leaves the browser: Section, factor, requirement card, retrieved excerpts, and draft text when you run it. Processor: Voyage AI for retrieval query; Anthropic for questions. Storage: One ai_use_log row per run at critique level without draft or questions. Retention: Same as AI-use log. Deletion: Delete my data or application delete.
- What changed visit time. Leaves the browser: None beyond the authenticated session. Processor: GrantAmp D1 user_visits. Storage: Last opened time for the what changed page. Retention: Until Delete my data. Deletion: Delete my data.
- Rate limiting. Leaves the browser: Client address is hashed, not stored. Processor: GrantAmp D1 rate_limits table. Storage: One way hash keys with counts. Retention: Two days, then daily cron purge. Deletion: Automatic purge.
- First-party site counts. Leaves the browser: No person fields; optional public path or plan name as dimension. Processor: GrantAmp D1 metric_counts. Storage: Metric name, UTC day, dimension, count. Retention: Rows remain in D1; the admin view reads the last ninety UTC days. Deletion: Not person specific.
- Guide Notice alerts. Leaves the browser: Email address and funding opportunity preference. Processor: GrantAmp D1; Resend for delivery. Storage: alert_subscribers (no user_id). Retention: Unconfirmed sign ups deleted after seven days. Confirmed rows until unsubscribe. Deletion: Unsubscribe link or purge of unconfirmed rows.
- Stripe billing. Leaves the browser: Payment details on Stripe's pages only. Processor: Stripe; GrantAmp D1 for entitlements and billing_customers. Storage: Stripe customer id, plan, status, period end; stripe_events ids for thirty days. Retention: Entitlements while active; stripe_events ledger thirty days. Deletion: Delete my data removes GrantAmp billing rows, not Stripe's payment record.
Encryption at rest
Saved drafts and optional AI-use prompts use AES-GCM. Each person has a random data key. The data key is wrapped under the DRAFT_KEY Worker secret and stored in draft_keys; the plaintext key never reaches D1 or a log.
Additional authenticated data binds each draft ciphertext to the application id and workspace element so a row cannot be moved to another workspace and decrypted there.
Rotation of DRAFT_KEY re wraps the small draft_keys rows; individual draft ciphertext is not re encrypted. Delete my data removes draft_keys so saved drafts become unreadable even if a backup existed.
Access controls
Signed in routes require a verified Clerk session at the Worker and again in the Python container before any application data is read or written.
Application rows are scoped to the signed in user id. The citation cache holds no user id by design.
Rate limit counters use one way hashes of the address or account id and the UTC day. Rows are purged after two days.
Administration is limited to Clerk user ids listed in ADMIN_USER_IDS. Those accounts are required to use multi factor authentication in Clerk.
Backups and restore
Application data lives in Cloudflare D1. GrantAmp does not run its own database servers. Cloudflare operates the service; restore after platform loss follows Cloudflare's processes.
The DRAFT_KEY secret must be held outside the repository. Losing it makes saved drafts unreadable with no recovery.
Incident response
GrantAmp treats a suspected breach of customer data as urgent. The first step is to contain the issue, preserve logs, and assess whether unpublished research or account data left GrantAmp's control.
When notification is required, affected account holders are emailed at the address on the account, and procurement contacts receive the same facts GrantAmp gives account holders.
Staff follow docs/trust/incident-response-runbook.md in this repository. HECVAT Lite draft answers are in docs/trust/hecvat-lite-answers.yaml; the retention schedule is docs/trust/retention-schedule.yaml.
Report a vulnerability
Send reports to security@grantamp.com. Include steps to reproduce, what you believe is affected, and your contact address. GrantAmp aims to acknowledge reports within three business days.
General product questions belong at hello@grantamp.com.
Changes
When this page changes, the date below changes.