---
title: "Keep files and search indexes apart by · Agent Wranglers"
url: https://agentwranglers.se/playbook/data/multi-tenancy/tenant-scoped-storage
id: DAT-69
level: Recommended
updated: 2026-10-22
tokens: 978
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Keep files and search indexes apart by tenant

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Multi-tenancy](https://agentwranglers.se/playbook/data/multi-tenancy.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-22.

- ID: DAT-69
- Level: Recommended
- Chapter: [Multi-tenancy](https://agentwranglers.se/playbook/data/multi-tenancy.md)
- Rule: Store each tenant's files under a path that starts with its tenant ID. Filter every search and vector query by tenant on the server, inside the query.
- Check: A listing of the bucket finds 0 objects outside `tenants/<id>/`. Signed in as tenant A, ask for a download link to a key under tenant B's prefix, and the server refuses. A search as tenant A for a word that only tenant B's documents hold returns 0 hits.
- How: Use object keys such as `tenants/481/invoices/2026-10.pdf`. Build the key on the server from the session's tenant, never from a request field. Check the prefix again before you sign a download link, as [Serve private files through short-lived links](https://agentwranglers.se/playbook/api-design/files-and-uploads/signed-downloads.md) describes. The prefix also makes a per-tenant export, copy or delete one listing. Tenants with their own database can get their own bucket. Search engines and vector stores need the tenant filter inside the query, as [Filter search results by access inside the query](https://agentwranglers.se/playbook/data/search/search-access-filter.md) shows. Cache keys carry the tenant, as [Put a format version in every cache key](https://agentwranglers.se/playbook/scaling/caching/versioned-cache-keys.md) says.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### JavaScript example

```js
export function fileKey(session, kind, name) {
  if (!/^[\w.-]+$/.test(name)) throw new Error('bad file name');
  return `tenants/${session.tenantId}/${kind}/${name}`;
}

export const ownsKey = (session, key) => key.startsWith(`tenants/${session.tenantId}/`);
```

### Python example

```python
import re

def file_key(session, kind: str, name: str) -> str:
    if not re.fullmatch(r"[\w.-]+", name):
        raise ValueError("bad file name")
    return f"tenants/{session.tenant_id}/{kind}/{name}"

def owns_key(session, key: str) -> bool:
    return key.startswith(f"tenants/{session.tenant_id}/")
```

## Sources

- [OWASP Multi-Tenant Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Multi_Tenant_Security_Cheat_Sheet.html)

## Related rules

- API-62 [Serve private files through short-lived links](https://agentwranglers.se/playbook/api-design/files-and-uploads/signed-downloads.md) in API design
- DAT-61 [Filter search results by access inside the query](https://agentwranglers.se/playbook/data/search/search-access-filter.md) in Data and databases
- SCL-12 [Put a format version in every cache key](https://agentwranglers.se/playbook/scaling/caching/versioned-cache-keys.md) in Scaling

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/data/multi-tenancy/tenant-scoped-storage">Agent Wranglers data and databases playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Run every background job inside its tenant](https://agentwranglers.se/playbook/data/multi-tenancy/tenant-context-in-jobs.md)
- Next: [Put the tenant on every log line and trace](https://agentwranglers.se/playbook/data/multi-tenancy/tenant-in-logs.md)
- [Multi-tenancy](https://agentwranglers.se/playbook/data/multi-tenancy.md)
