Security model
Written for the person reviewing it.
One organization reading another's numbers is the worst failure this platform could have. Everything below is arranged around preventing that, and the rules are structural, so breaking one should require deleting code rather than forgetting a check.
This page states the model and then states what we have not proven. If you are compiling a vendor assessment, the second part is the one worth reading twice.
The rules
Thirteen non-negotiables.
| # | Rule | How it is enforced |
|---|---|---|
| 1 | Only the guard binds a project | Not a tool argument, not a URL, not a token claim. One middleware resolves it from a live grant and stamps it on the request. |
| 2 | No scope, no connection | The component that reads holds no connection string. It asks for one on every open, so a tool with no bound project cannot open anything. |
| 3 | Anything touching data is request-scoped | A long-lived object could outlive one request and be handed to the next. None exists on that path. |
| 4 | Caches are keyed by project and re-assert on read | A cache hit that belongs to another project is discarded rather than returned. |
| 5 | Deny by default | Empty skill list grants nothing. Unknown profile expands to nothing. Unrecognised tool is assumed to need a database. |
| 6 | Customer organizations cannot cross organizations | Enforced where grants are created and again where they are used. |
| 7 | Token audiences are bound to the connector host | A token for one client's address cannot be replayed against another's. |
| 8 | Fail closed on every unknown | No email, no grant, no project, ambiguous project, unreachable control plane: all refuse. Outside development the service refuses to start at all without auth and a control plane. |
| 9 | Every narrowing is an intersection | Four gates, each a pure function that can only remove. No layer can grant what another refused. |
| 10 | A client's contributions run only on its own project | Tools and everything else a pack contributes, checked at creation and again at dispatch. |
| 11 | Refuse, never guess, when a target is ambiguous | Two candidates and no default is a refusal with the list. |
| 12 | Tenant-authored text is data, never instruction | Arrives after every decision and after the read, capped, labelled untrusted, and unable to reach another project's session. |
| 13 | A refusal never teaches the caller about another client | Not whether a project exists, not who owns a tool, not another organization's identifiers. |
These are covered by a test suite that runs offline with no database and no network, plus a set against a real SQL Server. A change that weakens one is treated as a security change and gets an adversarial review rather than a normal one.
Isolation
Isolation is the grant, not the deployment.
One service serves every client, and a request reaches exactly the one project the caller holds a live grant on. That is a deliberate choice with a real trade-off, so here is the trade-off.
Why not one deployment per client
It was seriously considered and it stays available. It was not chosen because N deployments per engine change is exactly the per-client maintenance cost that makes small clients uneconomic, and unmaintained instances are their own security problem.
If your review requires process isolation
The code supports it unchanged: a second instance of the same service with only your projects reachable. Ask, and it is a deployment decision rather than a redesign. We would rather have that conversation than pretend the shared model suits everybody.
Identity
Who you are, and what may reach what, are answered by different systems.
Your identity provider answers
- Who is this. Verified through your own Microsoft work account.
- Are they still here. Joiners and leavers stay your existing process.
We answer
- What may they reach. From a grant, in our control plane.
- What happened. The audit trail.
Keeping that split is what makes revocation a database edit that takes effect on the next call, and it means we hold no directory, no passwords and no group memberships. The broker that federates sign-in holds OAuth machinery only: it knows nothing about clients, projects or entitlements.
Not yet proven
What we would tell you in the meeting anyway.
A security page that lists only strengths is a marketing page. These are the open items as they stand today.
Answer quality is not yet measured here
There is a difference between "the tool answered" and "the tool answered correctly", and the harness that measures the second has not been brought across yet. Treat accuracy as something to verify in your own evaluation rather than something we have proven.
Reviews are internal so far
Adversarial isolation reviews have been run repeatedly against the code and their findings recorded and fixed. They were run by us. An external penetration test is not yet done.
Append-only is an application guarantee
No feature can alter an audit row and the console offers no path to it. That is not the same as write-once storage. If your review requires the cryptographic version, say so early.
Certification status, with dates
Published as a status rather than a badge wall. Ask and you get the honest position, including the parts that would not pass an audit today.
Where our own enforcement is the only one standing.
The next page publishes, per connected system, whether your person's own permissions are enforced by that system or only by us. Two of the four rows are us.