Skip to content

Security

The controls that exist, and the assurance that does not.

What protects your account and study records today, what has not been independently tested, and how to reach us if you find a problem.

Last reviewed: August 15, 2026 · Next scheduled review: September 14, 2026

What this page is

This describes the security controls that exist in the application today and the limits of that statement. It is not a certification, an audit report, or a claim that a third party has tested the system.

Where a control is described below, it means the behaviour is implemented in the application. It does not by itself prove the control is correctly configured in production, and we say so rather than implying more.

Controls in the application

Access decisions happen on the server
Paid access, answer checking, and grading are decided by server routes that recheck your session and entitlement on every request. Interface state is a convenience only — hiding or showing a button in the browser is never what grants access.
Authentication
Sign-in runs through WorkOS AuthKit. The application does not store your password, and the session travels in a secure, http-only cookie that page scripts cannot read.
Per-owner database rules
Private records — notebook entries, saved tutor chats, writing attempts and feedback, study plans, mock attempts — are defined with owner-scoped access policies, and browser-level grants are revoked on those tables so they cannot be read directly from a browser client. Automated isolation tests check that one account cannot read another's rows.
Privileged keys stay on the server
The privileged database key is loaded only in server-only modules and never carries a browser-public environment prefix. An automated repository check fails the build when a secret name is given a browser-public prefix or when privileged access is allowed to fall back to the anonymous key.
Request-origin checks on sensitive writes
The tutor and writing-feedback routes reject requests that do not come from this site's own pages, so another site cannot drive them with your session.
Signature-verified provider callbacks
Stripe and WorkOS webhooks are signature-verified against the raw request body before any of their data is trusted, and failures are logged without payloads, signatures, or provider exception text.
Browser security headers
Production responses are configured with a Content Security Policy, HTTP Strict Transport Security, frame denial, MIME-sniffing protection, a strict referrer policy, and a restrictive permissions policy. Checkout return pages and email preference pages additionally send private, no-store caching, and unsubscribe pages are marked not to be indexed.
Card details never reach us
Payment card entry happens on Stripe-hosted Checkout. The application stores Stripe identifiers and minimal subscription state, not card numbers.
AI request limits
Tutor and writing-feedback requests are bounded in size, capped by a per-account quota before any provider call, and cut off by a generation deadline so a stalled provider cannot hold a request open indefinitely.
ChatGPT credential isolation
If you connect ChatGPT, the credential is held in a private per-account directory on the server with owner-only permissions. It is never placed in browser storage, your profile, tutor history, analytics, or the application database.

What we do not claim

We have not had a penetration test, a security audit, or a certification such as SOC 2 or ISO 27001, and we will not imply otherwise. No independent party has reviewed the controls above.

The controls describe application behaviour. Production configuration — response headers as actually served, deployed secret scope, database policy execution, backup and restore, monitoring and alerting, and access reviews — has not been separately verified and recorded. We also do not claim that any provider's own security controls have been checked by us.

Security ownership and on-call escalation are not yet formally assigned, so we cannot promise a response time for a report.

Reporting a security concern

Email support@keiko.study or use the contact form. Describe what you found and how to reproduce it. Please do not include credentials, session tokens, another person's data, or extracted personal data in the report.

Please do not run automated scanning, load testing, or account takeover attempts against the live site, and do not access or modify data that is not yours. We do not operate a bug bounty and cannot offer a reward or a fixed remediation timeline. We will confirm receipt and tell you honestly what we can and cannot do.

Review and corrections

This page is reviewed on the schedule above, and again before a production release, after a change to authentication, payments, database access, or a provider, and after any security or privacy incident. If a statement here overstates what the application does, that is a defect — report it and we will correct the page.

Something on this page looks wrong, out of date, or does not match what you experience? Tell us and we will recheck it. You can also email support@keiko.study. Please leave passwords, payment details, and other people's personal information out of the message.

Report an issue with this page