Security and tenant isolation
The boundary is in the database, not in the screens in front of it.
A register of what an organization decided, spent and shipped — and now of what its agents did, which models saw the work, and what they were allowed to touch. Every record is separated at the database, encrypted in transit and at rest, and written to a trail nobody can edit afterwards.

Tenant isolation
One workspace cannot see another
Every record LockedIn Labs FDE stores carries the organization that owns it, and the database refuses any read or write that crosses that line.
The boundary is attached to the data rather than to the screens in front of it. Ordinary tenant requests use the caller’s database policies; privileged application functions enforce explicit session, organization and role checks.
Row Level Security is enabled on every table in the application schema, and on every one of them it is forced. Ordinary Row Level Security protects ordinary roles; FORCE also subjects table owners to policies unless they are superusers or hold BYPASSRLS. Those privileged operator paths can bypass row security, so FORCE alone does not establish their tenant isolation. A schema trigger applies the setting to new application tables.
The application checks the signed-in person’s organization and role as well. That check is the first line; the database boundary is the one that still holds if a query is ever written incorrectly. Relationships carry the organization too — a link from one customer’s work to another’s is declared on the pair of organization and record, so it does not satisfy the constraint and cannot be stored. A cross-tenant reference is a constraint violation, not a bug that behaves like a working join.
- scripts/prove-tenancy.mjs
- scripts/measure-posture.mjs
- src/app/app/[org]/settings/security/page.tsx
Verification
Recorded isolation evidence
Before a release ships, a real signed-in identity from one organization attempts to read and write the records of organizations it does not belong to, through the same interface a browser uses. Every attempt has to be refused.
The run enumerates what to try from the live schema rather than from a checklist, so anything added to the product is covered by the next release rather than by somebody remembering it. A table added with no organization on it is reported by name instead of being skipped quietly.
The same run attempts the deletions the trail is supposed to refuse, so the append-only boundary is proved by trying to cross it rather than asserted. Workspace security settings show current session and schema reads separately from the historical proof, with its recorded deployment and date.
Historical isolation proof · LockedIn Labs FDE External hosted service. Recorded 26 August 2026, 13 days ago: the run recorded no readable foreign row or accepted foreign write. This is the record of a run at a moment, not a live check. It does not verify LockedIn Labs FDE production or this installation.
- scripts/prove-tenancy.mjs
- scripts/gate.mjs
Agent authority
What an agent may reach is decided before it runs
The catalog of tools an agent can call is derived from the server that publishes them, and anything that writes is denied until a named person grants it.
A control a workspace deliberately made advisory is not a control it is protected by, so a refusal records whether the call was actually stopped or only watched.

- The catalog is derived, not typedWhat an agent can call comes from the server that publishes the tools, so the register cannot describe a door that does not exist or miss one that does.
- Writes are denied by defaultA tool that only reads is available. Anything that writes is refused until somebody with authority grants it, and the basis they gave is recorded beside the grant — a register whose default is “allowed” is a list rather than a control.
- The check precedes the doorThe permission is asked at the workspace endpoint before the tool executes, never alongside it — a check that runs in parallel with the work it authorizes has authorized nothing. The answer comes from the same function the workspace console reads, so the screen cannot describe a posture the door does not apply.
- A refusal is a recordIt names the tool, the reason, and whether the call was stopped or only watched. It never names the payload, and the stated reason is screened at write against the patterns that identify a person, so a refusal cannot itself become the leak.
- Nine operating policiesA run may not widen its own permissions, may not pipe fetched bytes straight into an interpreter, may not carry regulated content past its approved boundary, and may not accept its own output. Each is adopted by a named person at a stated enforcement level, and which are blocking is recorded rather than assumed.
- Silence is never a passA policy with no verdict on a run reads as not evaluated — never as passed. Verdicts are append-only, and a waiver that names nobody is refused by the database. Correcting a verdict means recording a new run, which is the honest shape.
- supabase/migrations/20260820190000_tool_permission.sql
- src/app/api/mcp/route.ts
- src/lib/tool-permission/gate.ts
- supabase/migrations/20260820020000_agentic_harness.sql
The AI control plane
Which models saw the work, and where they run
Models are approved one at a time and recorded with where they run, and each approval states in writing whether that model may process regulated content.
No credential is stored on a register a member can read. The pointer to the key and the key’s fingerprint are withheld from every workspace role, and the runtime reaches the secret through a privileged function that hands it to nobody.
- On premisesRuns on hardware this organization controls. Prompts do not leave the network.
- Private cloudA tenant-isolated deployment under contract. Handling is governed by that agreement rather than public terms.
- Vendor hostedA public API. Work sent here leaves the organization's boundary.
- supabase/migrations/20260820100000_provider_credentials.sql
- supabase/migrations/20260820200000_ai_credential_repair.sql
- src/lib/harness/model.ts
Encryption
Encrypted in transit and at rest
Both are provided by the managed platforms this deployment runs on, and both are stated here as fact rather than as a contractual undertaking.
- In transitEvery connection — browser to application, application to database — is TLS 1.2 or above. There is no unencrypted listener to reach.
- At restThe database and its backups are stored encrypted with AES-256 on managed infrastructure.
- Where it sitsCustomer data is held in the United States and nowhere else. Pages that carry no customer data are cached on a global network, which is why the site loads quickly from anywhere without any register content leaving the country.
Regions, key management and the limits of what we will put in a contract are set out in control detail.
Access and roles
Only the people you put in the workspace
A new account reaches nothing until an administrator places it in one workspace at one role. To somebody outside a workspace, the database answers exactly as it would to a stranger.
There is no cross-organization role and no global search. Least privilege here is the default state rather than a setting somebody has to remember to switch on.
- Two kinds of authority, kept apartAdministering a workspace and holding authority over delivery evidence are deliberately different grades, so managing membership does not carry the power to publish evidence, change billing or transfer ownership.
- Two-step verificationAny member can enroll a time-based code from an authenticator app. Once enrolled it cannot be skipped, and enrollment issues single-use recovery codes that are shown once and never emailed. No support process here can remove somebody’s second factor on request.
- Passwords are never ours to loseCredentials are exchanged with the identity service; this application never receives, stores or logs a password or a verification code. Passwords must be at least twelve characters and are checked against a public breach corpus and refused if they appear in it.
- Sessions expire, and privileged acts re-askA session ends after eight hours idle or twelve hours in total, and ending it revokes it at the identity service rather than only clearing the browser. Changing how people sign in to a workspace requires proving your identity again within the last fifteen minutes, and removing your own second factor requires that factor or an unspent recovery code.
- An act is somebody's actCustody triggers take the actor from the authenticated session rather than from anything the client sends, and a session with no identity behind it cannot approve a model, adopt a policy or grant a tool at all — the database refuses the write and says why.
- Single sign-onSAML 2.0 for Microsoft Entra ID and other standards-based providers is built into the product and enabled per deployment during onboarding. Its current activation status is stated in control detail.
The record
A trail that cannot be rewritten
Every act that changes what the register claims is appended to a trail: who did it, what changed and when.
The actor comes from the authenticated session rather than from anything the client sends. Deletion is blocked for workspace users, for owners and for privileged platform roles, and each release proves that boundary by attempting the deletion and being refused.
The trail is kept for the life of the tenancy. It does not roll off on a schedule and it is not something a plan can buy more of.
Evidence that leaves the building
Deck and trail exports carry an Ed25519 receipt over canonical bytes, and the public key travels inside the receipt.
The receipt holds the counts with their denominators, the acceptances, and the commit the export was pinned to. Anyone holding it can check it in their own browser at /verify — no account, and no call back to us — or with their own code, because the format and the canonicalization are published.
A claim whose count exceeds its own denominator is not rounded: the receipt is not issued. There is no partial receipt.
- src/lib/evidence/receipt.ts
- src/lib/evidence/canonical.ts
- src/app/verify/page.tsx
Disclosure
Reporting a vulnerability
There is a monitored security mailbox and a published disclosure policy.
The mailbox was verified end to end with a real message before this page named it, because an address that bounces silently turns a researcher trying to help into one who concludes nobody is listening.
Security contact: security@lockedinlabs.ai — also published machine-readably at security.txt (RFC 9116) with the scope notes. Tenant isolation is in scope and is the finding we most want.
Availability
Availability and recovery
What this deployment does today, and where the commitments about it actually live.
- BackupsDaily encrypted backups with point-in-time recovery, managed at the database platform layer.
- Dependency postureDependency advisories are triaged for reachability, and the tests that establish an advisory is unreachable are kept so the classification can be re-checked rather than believed.
Recovery objectives and support commitments are commercial terms, settled in the agreement for the estate in question. What this deployment does and does not commit to today is stated in control detail.
Subprocessors
Who else handles a workspace’s data
The services that handle customer data on our behalf, and what each one receives. Notice and objection rights are established in commercial terms.
| Subprocessor | What it receives |
|---|---|
| Supabase | The database, authentication identities and file storage. |
| Netlify | Request metadata, and the rendered HTML of every page. |
| Resend | The email address of anyone invited to a workspace. |
| Stripe | Billing contact and payment details for a paid plan. Card numbers are entered on Stripe’s own page and never reach this application. |
| Google Gemini (optional voice assistant) | Only when the assistant is enabled: a workspace brief scoped to what the signed-in person may already read — the workspace name, selected project keys, titles and states, and aggregate register counts — plus the live conversation’s audio and transcriptions. It receives nothing from this application when the assistant is not enabled. |
A model a workspace approves under the control plane is not on this list: those are the customer’s own arrangements, made under the customer’s own contracts, and the register records where each one runs so that the answer belongs to them rather than to us.
Assurance
Compliance and assurance
Under data-protection law your organization is the controller of its register content and LockedIn Labs FDE is its processor.
A data processing agreement, standard contractual clauses, a business associate agreement (BAA) where one is needed, incident-notification terms and deletion undertakings are settled in the enterprise agreement.
LockedIn Labs FDE holds no third-party attestation today. SOC 2 Type II, HITRUST and FedRAMP authorization are not held, and neither is ISO/IEC 27001. The product is not PCI DSS assessed and stores no card data — card details are entered on Stripe’s own page and never reach this application. We publish that here rather than in a footnote, because a trust badge that turns out to be a roadmap is the thing a reviewer never forgives.
What we offer instead is the mechanism and the dated evidence: the controls above, the release verification, the files under each one that a reviewer can open, and a control-detail page that answers a questionnaire without waiting for a call. Nothing the platform produces is described as certified.
The privacy notice covers what is collected and the rights a person can exercise. The terms carry the contractual counterparts of the limits stated here, and control detail carries the rest of what is not implemented.
Security review
Everything above can be checked, not just read
Control detail is written for the questionnaire: mechanisms stated precisely, the boundary of each one, and what is not implemented. Send anything it does not answer to the security team and you will get a direct answer rather than a deflection.