Security and subprocessors
Effective
This is the page to forward to a district technology director. It names where student data is stored, every company that touches it, and how one teacher’s caseload is kept out of another’s. It also says plainly what we do not claim.
For what is collected in the first place, see Privacy.
What is held, in one paragraph
A student record is initials, a grade band, and an optional display name that is blank by default and never required. Date of birth, district or state student ID, address, guardian contact, disability category and photographs are not fields that exist in the database — not defaults that are empty. Printed sheets and collection links carry initials only, always. Attached to a student are their goals as the teacher wrote them, the generated probe sheets, the collected scores, and the accommodation log. The full list is on Privacy.
How one caseload is kept out of another
This is usually the question behind the question, so here is the mechanism rather than an assurance.
- Row-level security on every table holding student data, enforced inside Postgres. Access is a property of the database, not of our code remembering to add a filter to a query.
- Two database roles, and the distinction is load-bearing. A table’s owner bypasses that table’s own security policies. So the role that owns the schema is used only by migrations and is not available to the running application; the role the application connects as owns nothing and has no privilege to bypass a policy. A single role for both would have given us row-level security that never applied — which is worse than none, because it looks safe. Our migrations refuse to run if the application role is ever granted that privilege.
- Every student query runs inside a transaction that sets the signed-in teacher’s identity for those policies to read. There is one code path that can do this and our build fails if any other part of the application opens a database connection.
- Referential integrity carries the tenant. A goal row whose owner disagrees with its student’s owner cannot be inserted at all — the foreign key is composite. Isolation is therefore not only a policy but a constraint.
- Student data is read and written only on the server. The browser never queries the database, which is also the only way a field can genuinely be withheld rather than hidden.
- Deny by default on every route. Authentication is an allow-list of five public pages; anything else requires a session. A screen added next month is protected without anyone remembering to protect it.
Subprocessors
Every company in the chain, what it is for, where it holds data, and whether student data reaches it. This list is complete as of the effective date above.
| Company | Purpose | Region | Student data |
|---|---|---|---|
| Neon | The database. Every student record, goal, probe sheet and data point. | United States — AWS US East 2 (Ohio) | Yes — all of it |
| Google Cloud / Firebase App Hosting | Runs the application and serves every page. Processes student data in memory while rendering a screen or a PDF; stores none of it. | United States | In transit only |
| Clerk | Sign-in and session management for teachers. | United States | No — teacher email only |
| Anthropic | Parses a pasted IEP goal, drafts a goal, and generates reading passages. Receives goal text, initials and grade band. Not used to train models. | United States | Yes — goal text, initials, grade band |
| Sentry | Error reports when something breaks. Configured with personal information off and request bodies scrubbed. | United States — region is permanent and cannot be changed | No — by configuration |
| Resend | Transactional email: the weekly reminder, and collection links. | United States | No — teacher email and initials in a link |
| Cloudflare | The domain and DNS today. Private object storage for encrypted backups and work-sample photographs is specified but not yet in use; when it is, buckets are private with signed URLs only. | United States | Not yet — backups and work samples when enabled |
| PostHog | Analytics on the public marketing pages only. Never loaded on any page that can display student data. | United States — US cloud | No |
| Google Analytics | Visit counts on the public marketing pages only. Never loaded on any page that can display student data. | United States | No |
On the two analytics rows. Google Analytics and PostHog load on the public marketing pages — the home page and these legal pages — and on nothing else. That is enforced in our codebase by an automated check that fails our build if an analytics script is referenced from any route that can render a student record, rather than by a convention someone has to remember. Once a teacher signs in, there is no third-party analytics code on the page at all.
On the Anthropic row, since it is the one most likely to need a policy decision on your side: a goal’s text, the student’s initials and their grade band are sent when a teacher asks us to parse a pasted goal, draft one, or generate a reading passage. Under Anthropic’s commercial API terms that data is not used to train their models. If your policy prohibits sending any student-related text to a model vendor, the rest of the product — the probe stack, data collection, the caseload view, the graph, accommodations — works without those three features.
Data processing agreement
We will sign a data processing agreement. Email privacy@omibrook.com with your district’s own template and we will return it signed, or ask us for ours.
We act as a service provider to the school under the teacher’s direction. The records are the school’s; we store and process them on its behalf, use them for no other purpose, and will delete them on request. We do not sell data, do not use it for advertising, and do not use it to train models.
What we do not claim
Stated here rather than left to be discovered, because a vendor who overstates this is a vendor you will have to re-audit later.
- We are not SOC 2 or ISO 27001 certified. With our vendors those programmes begin at several hundred dollars a month, and Omibrook is operated by one person. We cannot claim to run on a certified platform and we will not imply it.
- We have no dedicated security team and no 24/7 incident rota.
- We do not offer SSO, Clever, ClassLink or roster sync. These are deliberate product non-goals, not a roadmap item. Teachers sign in with email or a Google account and enter a caseload by hand, which takes a few minutes for twenty students.
- We have not had a third-party penetration test.
What we offer instead is the three things a district actually asks for and we genuinely control: a signable data processing agreement, a US hosting statement that is true and that cannot quietly stop being true, and the complete subprocessor list above.
Operator account security
Worth naming because for a product this size it is the security posture: an owner credential can read every record, so the accounts above are protected with two-factor authentication using an authenticator app rather than SMS. Secrets live in the hosting platform’s secret manager and never in our source code, which is checked automatically on every change. Dependency scanning blocks a release on a high-severity advisory in anything that ships.
If something goes wrong
If student data is exposed, we will email every affected account holder with what happened, what was in it and what we have done, without waiting to have a complete picture first — a district needs to start its own notification clock, and that matters more than our report being tidy. We will support your own notification obligations with whatever detail you need.
To report a vulnerability, email privacy@omibrook.com. We will acknowledge within three working days. We have no bug bounty and will not pretend to run one, but we will credit you if you want it and we will not threaten you.
Still need something
If a question your district needs answered is not on this page, that is a gap in the page and we would like to know. Email privacy@omibrook.com.