> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ironlabs.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Security & Isolation

> What is guaranteed to be separate inside IronLabs — and the mechanism that enforces each boundary.

IronLabs commits to specific negative guarantees: things that **never** cross tenant or product boundaries. This page lists them, the boundary they apply to, and the underlying mechanism — so you can verify the guarantee, not just trust it.

## Isolation guarantees

| Boundary                              | Guarantee                                                                                                                                                             | Mechanism                                                                                                                                                                                                                        |
| ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Tenant data**                       | API keys, trained Custom Routers, training datasets, and usage logs are **never shared across `userId`**.                                                             | Every row in PostgreSQL carries a `userId` foreign key. Clerk auth validates the user on every dashboard request; `validate_token` validates the API key on every router call. There is no shared-mutable cache between tenants. |
| **Model traffic**                     | A request dispatched to provider X is **never logged into provider Y**.                                                                                               | Per-call provider routing. No cross-provider retry happens unless you explicitly populate `fallback_models`.                                                                                                                     |
| **Custom Routers**                    | Trained routers are **never callable across users** — `model_id` is scoped to the training `userId`.                                                                  | `CustomRouter.userId` is enforced in `db_utils.can_user_create_router` and `get_router_model`. Calling another user's `model_id` returns `404`, not `403` — we don't acknowledge cross-tenant existence.                         |
| **AgentOpt sandboxes**                | Each optimization **iteration** runs in an **isolated Modal Sandbox**. No filesystem state, no network state, and no in-memory state survives across iterations.      | Modal Sandbox provides container-level isolation; the sandbox is destroyed and recreated per iteration. Code, dataset, and dependencies are re-mounted from your uploaded ZIP each time.                                         |
| **Provider keys (per-provider mode)** | When you supply your own `providers` config in the Node SDK, those keys are **never sent to the IronLabs routing API**.                                               | Resolution happens client-side in the SDK before the request leaves your process. The routing API receives a pre-resolved gateway URL and your IronLabs key only.                                                                |
| **Prompt-Opt OpenRouter keys**        | Optimizer-model calls (GEPA / MIPROv2) hit OpenRouter directly using **your** OpenRouter key. IronLabs neither stores it long-term nor uses it for any other purpose. | The key is held in memory for the duration of the optimization job and discarded when the job finalizes. Audit trail in Langfuse.                                                                                                |

## What this means in practice

* **Cross-tenant data leak through routing.** Not possible — the router's input is a single tenant's message; the classifier output is consumed inline and discarded; the only persisted artifact is `ModelSelectUsage`, which is `userId`-scoped.
* **A neighboring user's bad-faith Custom Router affecting your routing.** Not possible — your requests route through the pre-trained router unless **you** set `routerId` to one **you** own.
* **A leaked AgentOpt iteration leaving state behind.** Not possible — sandboxes are torn down per iteration. The only artifact that survives is the iteration's checkpoint row in `AgentOptRuns` (your `userId`).
* **Provider key exfiltration via a logged request.** Not possible in per-provider mode — keys never traverse our backend. In gateway mode (OpenRouter, LLM Gateway), the key is stored in your account's encrypted secrets and only injected at egress.

## Architecture, in one sentence

All requests terminate at the FastAPI gateway on Modal; per-tenant state lives in `userId`-scoped rows in PostgreSQL; there is no peer-to-peer state between tenants, between routers, or between optimization runs.

## What we do **not** guarantee

Honesty matters. These are not currently guaranteed:

* **At-rest encryption of training datasets.** Datasets you upload to a public URL for Custom Router training are downloaded into Modal Volumes and persisted in the trained model. If the dataset itself is sensitive, redact it before uploading.
* **Cross-region failover.** A single region outage will produce errors until that region recovers.
* **Provider-level isolation.** When a request is forwarded to OpenAI or Anthropic, that provider's security model applies; we cannot guarantee what they log on their side.

## Related

<CardGroup cols={2}>
  <Card title="Routing Lifecycle" icon="diagram-project" href="/refinery/essentials/routing-lifecycle">
    See where in the lifecycle each isolation boundary is enforced.
  </Card>

  <Card title="API Authentication" icon="key" href="/refinery/api-reference/introduction">
    Bearer-token scheme and key rotation.
  </Card>

  <Card title="AgentOpt" icon="robot" href="/refinery/essentials/agentopt">
    How the per-iteration sandbox is mounted.
  </Card>

  <Card title="Custom Router" icon="route" href="/refinery/essentials/custom_router">
    Where your training data lives after training.
  </Card>
</CardGroup>
