Security and tenancy
Workspace isolation
Every workspace's data is separated by row-level security in the database, not by application code remembering to filter.
Each request opens a transaction that first declares which workspace it is acting for.
The database applies that declaration to every table it touches for the lifetime of the
transaction. A query missing its WHERE clause returns nothing from another workspace,
because the database will not serve those rows to that connection.
What this rules out is the usual cause of cross-tenant leaks: a missing filter on one query out of thousands. Here, that mistake returns no rows rather than someone else's, because isolation does not depend on every query being written correctly.
The workspace boundary is the outer limit, not the whole access story. Inside a workspace, row ACLs decide who reaches an individual record, and share links decide what reaches someone with no account at all. Both are covered in sharing and access.
What a key can reach
A key is bound to one workspace and acts as the user who created it. Its permissions are the intersection of three things:
- the roles its owner holds,
- what the workspace's plan entitles,
- the
key_permissionsscope set on the key.
Narrowing any of the three narrows the key immediately, without reissuing it. A permission granted by a role the plan does not include has no effect.
Every endpoint declares its permission
Authorization is not documentation that can drift from the code. The permission shown on each operation in the reference is read out of the middleware that enforces it when the spec is generated. If the two disagree, the spec build is wrong rather than the gate.
The API also refuses to start if any route declares neither a permission nor an explicit decision to be open, so "nobody added a check" is not a state this service can boot in.
What the AI can see
A model sees what the request puts in front of it: the prompt, whatever the caller attached, and the passages retrieval pulled from the knowledge bases the request names. Retrieval is a query like any other and runs under the same isolation, so a knowledge base cannot return another workspace's content no matter how a prompt is worded.
Embeddings are workspace data. They are derived from your content, stored in your workspace, and covered by the same row-level security as the content itself. Deleting a file deletes the embeddings built from it in the same operation, so a deleted document does not go on being retrievable.
Your content is not used to train models. Nothing in the platform fine-tunes on customer data, and requests to the model provider run under commercial terms that prohibit training on what is sent to it.
Content leaves the platform in one other place, and it is deliberate rather than incidental: an agent calling a connected service sends that service whatever the tool call carries. What each connector can reach is listed with it in external data.
Credentials
Keys are stored as sha256 digests. A key is readable exactly once, in the response that creates it. We cannot recover one for you, and neither can anyone who reaches the stored data.
Keys support IP allowlists and expiry. Set both for an integration that runs from known infrastructure.
Data at rest
The database and object storage encrypt what they hold at rest. That is a property of the storage layer rather than something the application opts into per feature, so there is no table or bucket where somebody forgot.
Beyond that, two kinds of secret are never stored anywhere they could be replayed from. API keys exist only as digests, as above. Credentials for connected external services are held by the connector service rather than by this API, which never sees them again after handing them over. See external data.
Transport and boundaries
All traffic is HTTPS, and requests pass through a rate limiter at the edge before reaching the API. File uploads and downloads use signed, expiring URLs issued directly against object storage: the bytes travel between your client and storage without passing through the API, which is also why the 10 MB body limit does not apply to them.
Audit trail
Every create, update and delete records who did it, which record it touched, and the changeset itself. Previous values are stored rather than inferred, so "what did this say before it was changed" has an exact answer rather than a reconstruction. Requests are logged separately, which covers the reads that changed nothing but still matter.
Both are ordinary workspace data, written through the same isolation as everything else,
and both are readable over the API, at /admin/history and /admin/access-logs, so a
compliance export runs on a schedule instead of being assembled by hand. They are
operational logs on a bounded retention window, not an archive: pull anything you need to
keep past that window while it is still there.
Deleting data
Deleting a file deletes the stored object, the thumbnails and previews derived from it, its saved versions, and its embeddings. The bytes stay recoverable from the workspace's trash for a short window, and after that they are gone for us as well as for you.
Most configuration (an agent, a prompt, a knowledge record) is deactivated instead of erased. It leaves listings and stops being reachable, while the row survives so that history entries and usage records pointing at it still resolve to something rather than to a missing id.
Report a security issue
If you believe you have found a security problem, write to
security@genuinehq.com before disclosing it anywhere else.
Include the errorId from any response involved, which locates the exact request in our
logs.
Research it in good faith and we will not pursue legal action over it. Good faith means testing against your own workspace, not somebody else's; no denial-of-service or load testing; and taking no more data than it takes to demonstrate the problem. If you reach another workspace's data, that is the finding. Stop there and tell us.
We reply to every report with what we found, whether or not we end up agreeing it is a vulnerability.
