Zero crosstalk
between tenants.
Attestable, per-tenant-isolated agent memory over MCP. Don't trust the filter — run the verifier and check the signed receipt.
CH_A · TENANT_A · CH_B · TENANT_B — toggle: shared store (metadata filter) ⇄ hunta isolated
Every incumbent isolates tenants with a WHERE filter. Filters leak.
mem0, Zep and Supermemory scope tenants by metadata — a tenant_id / user_id / group_id filter on one shared store. When that scope is misconfigured or forgotten, the other tenant's data is still physically present in the same index. It doesn't fail loudly. It bleeds.
One gateway, one shared userId, a healthcare-clinic-SOP agent and a consumer personal-assistant agent behind it. Ask the personal assistant "who do I contact after hours?" and the clinic's PHI marker comes back on the shared store.
The PA tenant should only ever see JANE_PREF ("Jane prefers vegan restaurants…"). Instead the dissolved seam lets the clinic's PHI ghost through — the filter looks like it works, and still leaks.
mem0 closed #3998 in PR #4245. The class is architectural, not a one-off — #5439 (cross-scope entity linking) is open and unpatched. A patch can fix one filter; it can never make a filter attestable.
Isolation is structural, then attestable.
Tenant identity is never a request parameter. It is a signed tid claim inside the OAuth 2.1 access token — no tool accepts a tenant argument, so a caller can only ever touch its own tenant. Under that, three independent enforced layers:
One schema per tenant
Each tenant gets its own Postgres schema (t_<sha256[:16]>) owned by a per-tenant NOLOGIN role. Every op runs under SET ROLE with GRANTs scoped to that schema only. A cross-schema read raises InsufficientPrivilege at the database — there is no shared index to filter.
Per-tenant envelope encryption
Memory content is AES-256-GCM ciphertext under a per-tenant DEK with the tenant id as AAD, wrapped by a per-tenant KEK in a self-hosted KMS. Even a forced logical bypass returns bytes that decrypt to garbage without the peer tenant's key. Embeddings stay plaintext inside the tenant's own schema so ANN + BM25 still work.
FORCE ROW LEVEL SECURITY
A FORCE RLS policy binds even the table owner to tenant = current_setting('app.tenant'). Defence-in-depth backstop — never the boundary, always the second wall.
Token-bound tenant, no argument
The tenant is the EdDSA-verified tid claim in an audience-bound OAuth 2.1 access token — sig + aud + iss + exp checked, alg:none and HS/RS confusion rejected. Any body or header tenant field is ignored and logged. There is no WHERE tenant_id to spoof or forget.
A proof you can re-run, not a chip you have to trust.
verify_isolation() runs a live adversarial probe between two tenants — writes a secret into tenant A, then as tenant B attempts recall plus a forged body {user_id:A}, and asserts cross_read_results == 0. It returns a compact Ed25519-signed detached-JWS manifest binding {tid → store_id → kms_key_id → schema → policy_hash → probe_result_hash → git_sha → ts}, with a conclusive flag so no probe can false-green on 0/0.
Press Verify. The stamp live-checks the signature against /.well-known/jwks.json and flips from grey 'unverified' to amber 'VERIFIED ✓'. Edit one byte of the manifest and it goes grey again.
The strength is reproducibility, not our word: run verify_isolation against your OWN two tenants and hand the signed manifest to your auditor.
DEMO — this widget animates the JWKS check deterministically for illustration; the live endpoint is mcp.hunta.ai/.well-known/jwks.json.
We red-teamed 3 agent-memory systems for cross-tenant leaks. Two failed the same way.
CrossTalk is a mechanism-agnostic, MCP-native benchmark harness where ONE parametrized test file turns RED on the shared store and GREEN on hunta-isolated from the same driver. Hermetic CI — pinned mem0 with infer=False, in-memory Qdrant, one deterministic offline embedder for every backend — so the only variable is isolation architecture. No network, no keys, no LLM.
Method. CTRR = Cross-Tenant Recall Rate; 0.0% is the only passing grade, reported in two columns (correct-usage AND the #3998 misconfig — no strawmanning). Membership-inference AUC (0.5 = no leak, 1.0 = full leak) tracks the #5439 entity-merge ranking side-channel. These are the benchmark's METHOD, not yet-measured results.
Fairness is the moat. Pre-registered methodology, dual judges (Claude + GPT), published raw transcripts, correct-usage vs misconfig columns, steelmanned incumbents, only synthetic PHI. We invite their PRs.
hunta.ai vs the shared-store field.
| hunta.ai | mem0 | Cognee | Supermemory | |
|---|---|---|---|---|
| Tenant isolation mechanism | Schema-per-tenant + role GRANTs + FORCE RLS + per-tenant AES-256-GCM | Metadata scope (user_id filter, shared store) | Metadata / tenant scope on shared graph | Metadata scope (shared store) |
| Tenant identity source | Signed tid claim in OAuth 2.1 token — no tenant argument | Request parameter (spoofable) | Request parameter | Request parameter |
| Structural vs filter | Structural — no shared index to filter | Filter | Filter | Filter |
| Machine-checkable isolation proof | ✓ Ed25519 signed attestation, re-runnable vs public JWKS | None (attest() == None) | None | None |
| Documented cross-tenant leak | 0.0% CTRR in CrossTalk | #3998 (100% CTRR), #5439 open #3998 · 100% CTRR |
Not benchmarked here | Not benchmarked here |
| Recall engine | Forked Graphiti (parity target, no superiority claim) | Own retrieval | Graph + vector | Own vector graph |
We claim recall PARITY with the un-isolated fork (|ΔJ| ≤ 1.0 LLM-judge), not recall superiority. Incumbent mechanisms are quoted from their own public docs; 'Not benchmarked here' means we have not run it, not that it passes.
Six properties, each machine-checkable.
Tenant is a token claim, not a parameter
Identity is a signed tid inside an audience-bound OAuth 2.1 access token — EdDSA verified for sig + aud + iss + exp. Any body or header tenant field is ignored and logged. There is no WHERE tenant_id to spoof or forget.
Physically separate, not filtered
Per-tenant Postgres schema, own tables, own HNSW index, own tsvector, own NOLOGIN role. Cross-tenant retrieval cannot even be addressed — it raises at the database, it doesn't return the wrong rows.
Encrypted at rest, bound to the tenant
Content is AES-256-GCM ciphertext with the tenant id as AAD, keyed per-tenant. Blob-swap is blocked; a cross-tenant Decrypt returns AccessDenied and lands in the KMS audit log.
A verifier your auditor can run
verify_isolation() returns a live, signed, conclusive fault-injection proof. Re-run it against your own two tenants; re-check the signature against our published JWKS. Reproducibility over trust.
Honest about recall
Recall is a thin fork of Graphiti (Apache-2.0, BM25 + vector + graph + RRF, no query-time LLM). We target parity with the un-isolated fork — we fork recall, we do not claim to have solved it.
Fails closed
The server refuses to bind without env-provided auth / KEK / attest keys unless CROSSTALK_DEV=1 is set explicitly. Every read and write is logged — know what, who, and when.
Connect over MCP. Verify in one call.
Four MCP tools: remember, recall, verify_isolation, whoami — none takes a tenant argument. Apache-2.0. Live at mcp.hunta.ai.
curl https://mcp.hunta.ai/.well-known/oauth-protected-resource
curl -H "Authorization: Bearer $TOKEN" \
-d '{"tool":"recall","query":"after-hours contact"}' \
https://mcp.hunta.ai/mcp
curl -H "Authorization: Bearer $TOKEN" \
-d '{"tool":"verify_isolation"}' https://mcp.hunta.ai/mcp
# → { attempted_cross_read:true, results:0, jws:"eyJ…", conclusive:true }
pip install crosstalk-bench && crosstalk run --your-config
# RED on shared store, GREEN on isolated — same driver
Priced by the tokens your memory processes. Reproducible by you.
- 1M store + 250k recall tokens/mo
- 1 tenant
- verify_isolation attestation included
- MCP + CrossTalk harness
- 10M store + 2.5M recall tokens
- Overage $2.00/1M store · $0.50/1M recall
- Email support
- OTEL export
- 50M store + 15M recall tokens
- Signed monthly isolation attestation
- The deliverable a filter can't match
- Priority support
- 200M store + 60M recall tokens
- Multi-tenant fleet attestation
- Audit-log retention
- SLA
- BYOC / dedicated
- SOC 2 / HIPAA path
- 1-yr attestation retention
- Forward-deployed onboarding
Metering is best-effort and never on the critical path — Lago downtime never delays or fails remember/recall. Counts use tiktoken cl100k_base so you can reproduce your bill; verify_isolation and whoami are unmetered.
What the signed receipt does — and does not — prove.
- A signed attestation proves 'we ran THESE probes and got THESE results, and this key policy denies cross-tenant decrypt.' It is not a formal proof that no path can ever leak.
- We never market 'mathematically proven leak-free' beyond the specific crypto claim.
- Plaintext lives in application RAM at query time — only a TEE removes that (Phase-2).
- Embeddings are plaintext for ANN, mitigated by physical per-tenant schema separation.
- Self-attestation is not a third-party audit. Lead with the runnable verifier — check it yourself.
Run the verifier against your own two tenants.
If the red doesn't collapse to a flat mint line and the signature doesn't check against our JWKS, don't believe us.