# Cross-tenant invoice reads in a fictional API

Fictional example, not client work. The system, records, observations and test results below are invented to explain a reporting method. No live service was tested.

Specimen ID: EXAMPLE-AUTHZ-01

## Context

Imagine a billing application with separate customer tenants. An authenticated user can request an invoice by identifier. The read handler checks that a session is valid but, in this invented implementation, does not bind the requested invoice to the caller’s tenant. Its write handler has a separate role restriction.

## Intended access model

| Principal | Home tenant | Role | Intended access |
| --- | --- | --- | --- |
| Member A | Tenant A | Member | Read invoices belonging to Tenant A; no invoice updates. |
| Member B | Tenant B | Member | Read invoices belonging to Tenant B; no invoice updates. |
| Admin A | Tenant A | Tenant administrator | Administer permitted invoice actions within Tenant A only. |

## Preconditions

- The application’s documented policy isolates invoice data by tenant. A tenant administrator is not a global administrator.
- The caller has a valid member or tenant-administrator session. Authentication alone is not the policy being challenged.
- A requested invoice belongs to a different tenant. The fictional fixtures are A-INV-01 and B-INV-01; they contain no personal or production information.
- The caller can supply an object identifier. Identifier discovery, enumeration, and identifier entropy are separate questions; this example assumes the other fixture identifier is known.
- The read handler performs a direct object lookup without applying tenant scope. No claim is made about other handlers or services.

## Expected behavior

A request must satisfy both the permitted action and the caller’s tenant boundary before invoice content is returned. An otherwise valid session requesting another tenant’s invoice is denied without exposing the invoice body.

## Synthetic observed behavior

In the invented pre-fix behavior, Member A receives the B-INV-01 fixture. Member A can still read A-INV-01, unauthenticated access remains denied, and the separate role check prevents Member A from updating an invoice. Those working controls do not repair the cross-tenant read.

## Mechanism

The application treats “this caller is signed in” as sufficient permission to read “this invoice.” The missing relation is between the authenticated principal and the resource’s tenant. The trust boundary fails at object authorization, after successful authentication.

## Synthetic evidence matrix

| ID | Principal | Object | Action | Policy expects | Before (fictional) | Fix expectation |
| --- | --- | --- | --- | --- | --- | --- |
| E01 | Member A | A-INV-01 | Read | Allow | Allow | Allow |
| E02 | Member A | B-INV-01 | Read | Deny | Allow — finding | Deny |
| E03 | Member B | B-INV-01 | Read | Allow | Allow | Allow |
| E04 | Member A | A-INV-01 | Update | Deny | Deny | Deny |
| E05 | No session | B-INV-01 | Read | Deny | Deny | Deny |
| E06 | Admin A | B-INV-01 | Read | Deny | Allow — finding | Deny |

“Before” is the fictional vulnerable behavior. “After” is the proposed fix’s expected behavior, not a completed real-world retest. Allow means an invoice fixture is returned; deny means no invoice fixture content is returned. A real report would retain sanitized request/response evidence, the tested artifact and environment, timestamps, and reproducible prerequisites in an agreed private channel.

## Impact and bounds

- Within this model, a valid user can read another tenant’s invoice when its identifier is known. That violates the promised tenant confidentiality boundary.
- The affected capability is reading invoice data in this handler. The example does not establish invoice modification, unrestricted bulk export, account takeover, or compromise of other services.
- Practical severity would depend on the real invoice fields, identifier exposure, reachable populations, request limits, logging, and other relevant constraints. This specimen assigns no CVSS number or financial-loss estimate.

## Remediation

- Derive the caller’s tenant and permitted actions from trusted server-side identity and policy. Do not accept an unrestricted tenant value from the request as authorization.
- Apply tenant scope at resource selection or enforce an equivalent policy before serialization. Require both the correct tenant relation and the allowed action. Deny by default when either cannot be established.
- Preserve the existing role restrictions and unauthenticated-denial behavior. A fix that blocks every request would remove the reported read path while breaking legitimate use.
- Use the same authorization boundary for alternate read paths where they exist, such as downloads, list endpoints, caches and background exports. Their presence and impact would need separate investigation.
- Define the product’s behavior for a denied or unavailable object, including response content and logging. Do not leak protected fixture data through error details, caches, or debug output.

## Verification plan

- Repeat the E02 and E06 cross-tenant cases. Expected: No B-INV-01 content is returned to Member A or Admin A.
- Repeat E01 and E03 with their permitted tenants. Expected: Each member can still read the invoice that policy allows.
- Repeat the E04 role restriction and E05 missing-session case. Expected: Both remain denied; the fix does not weaken adjacent controls.
- Apply the same checks to the agreed patched artifact and relevant cache state. Expected: Record the exact version and environment, and confirm a previous response does not bypass the scoped handler.
- Review equivalent entry points found within the agreed scope. Expected: The same tenant/action policy is enforced, or remaining gaps are explicitly tracked.

## Counterexamples

- Adding a role check alone is insufficient: Admin A must still be denied Tenant B’s invoice.
- Hiding the invoice identifier in the interface is insufficient: a known foreign identifier must still be denied by the server.
- Making identifiers harder to guess can reduce discovery opportunities but does not establish permission to an already known object.
- Rejecting every invoice read is not a successful fix: the authorized baseline cases must continue to work.

## Decision ownership

In this example, the application engineering owner is accountable for the handler change and evidence; the product/security decision owner approves the intended tenant policy. The release owner decides whether the recorded results meet the agreed release condition. These are example responsibilities, not named client roles.

Do not mark this example resolved merely because code changed. Resolution requires the agreed tenant policy, a versioned fix, the negative and positive verification cases, and an explicit record of remaining uncertainty or accepted risk.

## Limitations

- This is a teaching specimen, not an audit report for an assessed organization or evidence of Web3Sec’s past client work.
- The fixture system, finding, observations, and outcomes are fictional. No endpoint, exploit attempt, client identity, credential, or production record is provided.
- There is no inference about the safety of a real application. A real review would identify scope, methodology, exclusions, environment, version, dates, evidence handling, and authorized activities.
- A successful bounded retest would establish only the behavior tested under the recorded conditions. It would not prove the absence of other authorization flaws.

Source: https://www.web3sec.news/sample-report
Related service: https://www.web3sec.news/services/web-api-pentesting
