Threat Model
Method: STRIDE across trust boundaries, mapped to the OWASP API Security Top 10 (2023), with attack trees for crown-jewel assets and a ranked risk register.
:::danger Critical risks Cross-tenant data leak and encryption key compromise are classified Critical. Every deployment must pass the cross-tenant isolation test before going to production. :::
1. Assets & Adversaries
Assets (what we protect):
- Tenant data — file bytes and metadata
- Credentials & encryption keys — tokens, API keys, DEKs, KEKs
- Audit log integrity — the tamper-evident record of actions
- Availability — service continuity and SLOs
- Namespace correctness — the file tree’s consistency guarantees
Cross-tenant confidentiality and key compromise are catastrophic (unrecoverable). Availability and integrity failures are severe but recoverable.
Adversaries:
- External attacker (unauthenticated)
- Malicious tenant or user (authenticated, attacking other tenants)
- Compromised credential or API key
- Malicious insider / rogue DBA
- Malicious plugin author
- Supply-chain attacker
- Anonymous public-link abuser
2. STRIDE by Trust Boundary
| STRIDE | Threat example | Boundary | Primary control |
|---|---|---|---|
| Spoofing | Stolen token / API key; forged tenant_id claim |
Edge | OAuth 2.1 + MFA; signed tokens; hashed keys |
| Tampering | Mutate another tenant’s object; alter manifest; edit audit record | Control / data | Object-level authz (BOLA); BLAKE3 content hashing; tamper-evident Merkle log |
| Repudiation | “I didn’t share that file” | All | Immutable, attributable audit log with Merkle proofs |
| Info disclosure | Cross-tenant read; cache/log leakage; presigned URL leak | Data / edge | RLS + defense-in-depth isolation; per-tenant envelope encryption; scoped short-TTL URLs |
| Denial of service | Request flood; expensive ops abuse; storage exhaustion | Edge / data | Layered rate limits + per-tenant quotas |
| Elevation of privilege | Self-elevate role; BFLA on admin API; plugin sandbox escape | Control | Deny-by-default RBAC; authorized role-change only; WASM capability sandbox |
3. OWASP API Top 10 (2023)
| # | Risk | BitVault exposure | Mitigation |
|---|---|---|---|
| API1 | Broken Object Level Authorization (BOLA) — ~40% of API attacks | Guess a node_id / share_id from another user or tenant |
Every object access → PDP check (principal, action, resource) and RLS; never trust client-supplied IDs |
| API2 | Broken Authentication | Credential stuffing, JWT exp not checked, token theft |
OAuth 2.1, MFA, refresh rotation + reuse detection, full JWT validation (exp/nbf/aud/iss/alg) |
| API3 | Broken Object Property Level Authorization | API returns or accepts fields a role shouldn’t see or set | Field-level authz; explicit allow-listed DTOs; never bind raw request bodies to domain models |
| API4 | Unrestricted Resource Consumption | Upload floods, search abuse, huge files | Per-tenant / per-key rate limits + quotas + size caps |
| API5 | Broken Function Level Authorization (BFLA) | A member calls an admin endpoint | Role checks per gRPC method, deny-by-default; admin routes explicitly gated and audited |
| API6 | Unrestricted Access to Sensitive Business Flows | Scripted mass public-link creation, bulk download, signup farms | Flow-level limits, CAPTCHA / step-up, anomaly detection |
| API7 | SSRF | Preview / transform / webhook fetches a URL → hits cloud metadata endpoint | Egress allow-lists; block link-local / metadata IPs; scoped HTTP in plugins |
| API8 | Security Misconfiguration | Open bucket, permissive CORS, verbose errors to clients | Hardened defaults, IaC + GitOps review, PodSecurity; no stack traces to clients |
| API9 | Improper Inventory Management | Forgotten API versions, debug routes | Versioned API + OpenAPI inventory (ADR-0015); deprecated versions decommissioned on schedule |
| API10 | Unsafe Consumption of APIs | Trusting external IdP / KMS / webhook response blindly | Validate all external responses; signed webhooks with HMAC verification |
4. Cross-Tenant Attack Vectors
These deserve explicit call-out because authentication and authorization alone do not prevent them:
- Forged
tenant_id— tenant context must derive from the verified token, resolved before any business logic, and re-checked on every authorization decision, never accepted from client input. - Cache-key collision —
prefs:{user_id}identical across tenants → tenant-prefix every Redis key by construction. - Connection-pool contamination — a global
tenant_idwritten during anawaitlets a concurrent request adopt it (identity swap) → request-scoped context + PgBouncer session pooling with mandatoryserver_reset_query. - SQLi overriding
tenant_id— parameterized queries at every call site; RLS as a backstop that cannot be bypassed by SQL injection. - Sensitive values in URLs — leak into access logs and
Refererheaders (CWE-532) → identifiers only in request body or headers, never in the query string. - Side-channels (dedup existence, timing) — per-tenant dedup scope (ADR-0018) prevents existence probes across tenants.
5. Attack Tree: Read Another Tenant’s File
flowchart TB
classDef g fill:#fecaca,stroke:#b91c1c,color:#111827;
classDef a fill:#fde68a,stroke:#b45309,color:#111827;
classDef m fill:#bbf7d0,stroke:#15803d,color:#111827;
G["GOAL: read tenant B's file as tenant A"]:::g
G --> A1["forge / alter tenant_id claim"]:::a --> M1["signed tokens + verify on every decision (RLS)"]:::m
G --> A2["BOLA: access B's node_id directly"]:::a --> M2["PDP object-authz + RLS backstop"]:::m
G --> A3["cache-key collision read"]:::a --> M3["tenant-prefixed cache keys"]:::m
G --> A4["connection-pool identity swap"]:::a --> M4["request-scoped context + server_reset_query"]:::m
G --> A5["search index cross-tenant hit"]:::a --> M5["tenant-scoped index + filter (ADR-0009)"]:::m
G --> A6["leaked / over-broad presigned URL"]:::a --> M6["scoped, short-TTL, exact-key URLs"]:::m
G --> A7["read B's backup / object directly"]:::a --> M7["per-tenant keys — crypto isolation"]:::m
Every branch is independently mitigated. Defense in depth means no single control failure exposes tenant data.
6. Attack Tree: Account / Tenant Takeover
flowchart TB
classDef g fill:#fecaca,stroke:#b91c1c,color:#111827;
classDef a fill:#fde68a,stroke:#b45309,color:#111827;
classDef m fill:#bbf7d0,stroke:#15803d,color:#111827;
G["GOAL: take over an account / org admin"]:::g
G --> A1["credential stuffing / brute force"]:::a --> M1["MFA + lockout + breach-password check"]:::m
G --> A2["steal access / refresh token"]:::a --> M2["short TTL + rotation + reuse detection + DPoP"]:::m
G --> A3["leaked API key (git / logs)"]:::a --> M3["hashed, scoped, rotatable + secret scanning"]:::m
G --> A4["session fixation / XSS"]:::a --> M4["secure cookies + CSP + httpOnly + SameSite=Strict"]:::m
G --> A5["self-elevate role"]:::a --> M5["deny-by-default authz on role change"]:::m
G --> A6["phishing OAuth consent"]:::a --> M6["exact redirect-URI match + PKCE mandatory"]:::m
7. Risk Register
| Risk | Likelihood | Impact | Severity | Key mitigation | Residual |
|---|---|---|---|---|---|
| Cross-tenant data leak (BOLA / isolation) | Medium | Critical | 🔴 Critical | PDP + RLS + cache / key / connection isolation | Low (defense-in-depth + CI tests) |
| Encryption key compromise | Low | Critical | 🔴 Critical | KMS, per-tenant keys, no export, rotation | Low |
| Account / API-key takeover | Medium | High | 🟠 High | MFA, token rotation, key hashing | Medium (human factor) |
| Public-link abuse / data exfiltration | Medium | High | 🟠 High | Scoped capability tokens, expiry, anomaly detection | Medium |
| DoS / resource exhaustion | High | Medium | 🟠 High | Layered rate limits + quotas | Low–medium |
| Audit tampering / repudiation | Low | High | 🟡 Medium | Tamper-evident Merkle log, separate trust domain | Low |
| SSRF via previews or plugins | Medium | Medium | 🟡 Medium | Egress allow-list, block metadata IPs | Low |
| Plugin sandbox escape | Low | High | 🟡 Medium | WASM capability sandbox + limits | Low |
| Supply-chain compromise | Low | Critical | 🟡 Medium | Signing, SBOM, SLSA, admission verification | Low |
| Insider / rogue DBA | Low | Critical | 🟡 Medium | Per-tenant encryption, least privilege, audit | Medium |
8. Keeping the Model Honest
- Continuous CI tests for top risks: the cross-tenant access test (forged
tenant_idblocked by RLS), BOLA fuzzing, token-reuse detection, rate-limit tests. - Pen testing + bug bounty on a scheduled cadence.
- Living document: revisited on every new trust boundary — new principal type, new external integration, new plugin capability.