2026 customs changesWhat it means

Data Isolation

How CargoLint separates each organization's data across request scoping, application query filters, database row-level security, and per-organization document storage.

Overview

Every account in CargoLint belongs to an organization, and an organization is the boundary for all data. Documents, shipments, parties, products, audit logs, and usage records are scoped to the organization that created them.

That boundary is enforced at four independent layers. Each one is sufficient on its own for the paths it covers, and they are arranged so that a defect in one is contained by the next.

Layer Where it runs What it enforces
Request scoping API Organization identity comes from the access token, not from request input
Query filters Application Every database query is automatically narrowed to the caller’s organization
Row-level security Database SQL Server itself refuses rows belonging to another organization
Container separation Storage Each organization’s files live in a dedicated blob container

Request scoping

Your organization is carried inside the access token issued at sign-in, as an organizationId claim. On every authenticated request, middleware reads that claim and establishes it as the organization context for the rest of the request.

Endpoints derive the organization from this context rather than from a path, query, or body parameter. Changing a request payload does not change which organization’s data is returned, because the identity is not something the client supplies.

Application query filters

The data access layer registers global query filters on every tenant-scoped entity. These filters are applied by the ORM to all queries against those entities, including queries built indirectly through joins and navigation properties.

The effect is that a query written as “all documents” resolves to “all documents belonging to this organization” before it reaches the database. There is no code path where a developer has to remember to add the organization condition, because the filter is attached to the entity type itself.

Database row-level security

Behind the application filters, SQL Server enforces the same rule independently.

A security policy named TenantIsolationPolicy applies a filter predicate to the tenant-scoped tables. When a request opens a database connection, the caller’s organization is stamped into the session with sp_set_session_context, marked read-only so it cannot be altered for the life of that session. The predicate compares each row’s organization against that session value and hides anything that does not match.

This matters because it holds even when the application layer is bypassed. Raw SQL, a hand-written query, or a mistake that disables the ORM filters still meets the database predicate. The policy is created with SCHEMABINDING, so the tables it protects cannot be altered in ways that would silently drop the protection.

Where a connection does not resolve an organization at all, such as background processing and platform operations, the predicate does not filter, and scoping on those paths is handled in the application layer.

Document storage

Uploaded files are not stored in a shared container with organization prefixes. Each organization gets a dedicated Azure Blob Storage container named for its organization ID, created on first use and configured with no public access.

Because the boundary is the container rather than a naming convention inside a shared container, storage-level access controls can be applied per organization, and a path-handling bug cannot resolve to another organization’s files.

Access to individual documents is granted through short-lived signed URLs scoped to a single blob, rather than by exposing container credentials.

Encryption

All documents are encrypted at rest. Organizations on the Enterprise plan additionally receive a dedicated encryption scope, set as the enforced default on their container so that uploads cannot be written outside it.

This resolution fails closed. If a per-organization encryption scope cannot be resolved for an Enterprise organization, the container is not created under account-level encryption as a fallback.

What you can verify

Isolation is designed to be checked rather than taken on faith:

  • Audit logs record every document access, including which user in which organization performed it. See Audit Logs.
  • Data export returns the complete contents of your account, which is also the complete set of what is scoped to you. See GDPR Compliance.
  • API keys and tokens are issued per organization, so a token from one account cannot read another account’s data through the API. See Authentication.