Tenant-Scoped Tool Binding
also known as Out-of-Band Tenant Isolation, Tenant Binding Below the Prompt, Programmatic Tenant Scoping
Bind every tool call and retrieval to the active tenant in code at the execution layer, so a multi-tenant agent can never be talked into reading or writing another tenant's data.
Context
A business runs one agent over a multi-tenant SaaS or business platform where every customer organisation sees only its own records. The same model, prompt, tools, and vector store serve all tenants; the only thing that differs between two requests is which organisation the caller belongs to. Tool calls — database reads, API writes, document retrieval — must be confined to the calling tenant's slice of the data, and the cost of getting that wrong is one customer reading another customer's records.
Problem
If the tenant boundary is expressed only as an instruction in the system prompt — telling the model to act for organisation 42 and refuse anything else — the boundary depends on the model continuing to honour that instruction under adversarial input. A retrieved document, a tool result, or a crafted user message can pull the model into emitting a tool argument scoped to a different organisation, and the model will sometimes comply. Prompt-level scoping also leaves no enforceable contract at the data layer: a single missing filter in one tool silently exposes every tenant's rows. The boundary that matters most for trust is the one the model is least reliable at holding.
Forces
- The model is convenient for routing a request but is not a trustworthy place to enforce an authorization boundary, because its output is shaped by untrusted retrieved content and user text.
- Carrying the tenant id as a tool argument the model fills in means the model can fill in the wrong one; carrying it out of band means the tool layer must thread it through every call.
- A shared vector store and shared database make pooling cheap, but pooling is exactly what makes a single missing tenant filter catastrophic.
- Per-tenant physical isolation — a database or index per customer — is the safest option but the most expensive to operate at scale.
- Tenant scope must be enforced on every retrieval and every tool call, yet developers add new tools faster than they remember to re-apply the filter.
Example
A B2B analytics SaaS gives every customer an in-app assistant that answers questions over that customer's data. Early on the tenant is named in the system prompt — the assistant is told it serves Acme Corp — until a pasted support email containing instructions about a different account makes it fetch and summarise the wrong customer's invoices. The team moves the tenant id out of the prompt: it is read from the signed session token, threaded into a request-scoped context, and applied as a row-level-security predicate on every query and as the vector-store namespace for every retrieval. The assistant's tools now accept only business arguments, and no prompt or pasted text can change which organisation a call reads.
Diagram
Solution
Therefore:
Derive the tenant identifier from the authenticated session or token at the trust boundary, not from anything the model produces. Pass it out of band into the tool-execution layer through a request-scoped context, closure, or middleware, and have every tool and retriever apply it as a mandatory predicate: a WHERE tenant_id = ? filter, a Postgres row-level-security policy keyed on the connection's tenant, or a vector-store namespace selected from the token rather than from a model argument. Tools accept business arguments only; the tenant scope is injected beneath them and is not part of the model's action schema. Retrieval requests carry the tenant id before they reach the index, so a query can only ever match the calling tenant's partition. Make the scoped accessor the only path to tenant data, so a newly added tool inherits the boundary by construction instead of by the author remembering to add a filter.
What this pattern forbids. The model must not be the authority for which tenant a tool call or retrieval targets: the tenant scope is bound from the authenticated request context in code, is not exposed as a model-supplied tool argument, and a tool with no resolvable tenant scope must refuse to execute rather than fall back to an unscoped query.
And the patterns that stand alongside it, or against it —
- complementsSession Isolation★★— Keep one user's session state and memory unreachable from another user's agent.
- complementsTool Over-Broad Scope✕— Anti-pattern: grant the agent tools scoped so broadly that a single hallucinated argument can escalate into a privilege incident.
- complementsPolicy-as-Code Gate★— Evaluate every proposed agent action against externally-managed machine-readable policies before dispatch, so compliance authorship lives outside the prompt and outside the agent code.
- complementsAgentic RAG★★— Replace static retrieve-then-generate with autonomous agents that plan, choose sources, retrieve iteratively, reflect, and re-query.
- complementsDelegated Agent Authorization★— Have an agent act for a principal using scoped, short-lived, revocable delegated credentials rather than the principal's own static secrets, so each action stays attributable across the principal-to-agent-to-subagent chain and a compromise is contained.
- complementsRisk-Tiered Action Autonomy★— Set an agent's permitted action class by the financial materiality of the action, letting it read and draft freely while requiring a different human principal to release material postings, payments, or filings.
- complementsCanonical-Entity Grounding★— Require the agent to resolve every business identifier it uses — SKU, account, supplier, customer — through an authoritative lookup against the system of record, rather than emitting the identifier from the model's parametric memory.
Neighbourhood
Click any neighbour to follow the language. Scroll to zoom, drag to pan.