Safeguard
Security Guides•

Should an API return 403 or 404 for another tenant's object?

Both are accepted by OWASP guidance. 404 hides that a record exists, 403 is more honest. How to choose, apply it consistently and test for it.

Safeguard Security Team
4 min read

Either can be correct. 403 says the caller is not allowed, while 404 avoids confirming that another tenant's record exists. For objects in other tenants, many teams return 404 so IDs cannot be probed. Pick one rule, apply it everywhere and test that responses do not differ.

What the codes mean

The OWASP REST Security Cheat Sheet describes 403 Forbidden as used when authentication succeeded but the authenticated user lacks permission for the requested resource, and 404 Not Found as used when a non-existent resource is requested. 401 means wrong or missing credentials.

The OWASP Authorization Regression Testing Cheat Sheet accepts both for the same case. Its assertion for horizontal escalation is that the system must return 403 Forbidden or 404 Not Found, to avoid information leakage about resource existence, and never 200 OK.

The trade-off

ChoiceBenefitCost
403Honest and easy to debug. Clients know it is a permission problemConfirms the object exists, which helps enumeration
404Reveals nothing about other tenants' recordsHarder to debug. A real missing record looks the same as a forbidden one

Existence leaks matter more across tenant boundaries than inside a tenant. If a user in tenant A can tell that invoice 9001 exists in tenant B, that is information they should not have, even if they cannot read it.

The OWASP multi-tenant sheet's sample code lines up with this. Its tenant-scoped lookup includes the tenant in the query, so a record from another tenant is simply not found, and its comment says to not reveal if it exists for another tenant. Its middleware, though, returns 403 when the caller has no membership in the tenant they named, because the problem there is the caller's tenant claim, not a single object.

A rule that works

  1. Caller not a member of the tenant they selected: 403.
  2. Object not in the caller's tenant: 404, because the scoped query finds nothing.
  3. Object in the caller's tenant but action not permitted: 403, since the caller already knows it exists.
  4. No credentials or invalid token: 401.

Write this table into your API guidelines so every team returns the same thing.

Make the responses indistinguishable

Choosing 404 is not enough if other signals differ.

  • Body. Use the same error body for a missing record and a hidden one.
  • Timing. A hidden record that triggers an extra permission query can answer more slowly. Aim for similar paths.
  • Headers. Do not leave debug headers that mention the owning tenant.
  • Logs and traces. Keep detail in server logs, not in the response. The OWASP sheet warns against exposing sensitive information in error messages.

How to test it

Create a record in tenant A. As a tenant B user, request it by ID with read, update and delete. Compare against a request for an ID that was never created. Status code, body and headers should match for the case you decided to hide. Repeat for list and search endpoints, which should simply omit the record.

Also confirm the status is not 200 anywhere, including for batch endpoints that return per-item results.

Try it yourself

Click through it at your own pace, or open it full screen. Look at how responses to unauthorized requests are compared.

Safeguard supports dependency scanning and policy gates for pull requests, so error-handling and framework libraries are inventoried. Try the free scan at gold.safeguard.sh/scan.

Quick check

Does returning 404 mean I do not need the check?

No. The check still has to run. A 404 is only the way you report the failed check.

Is 403 wrong for other tenants?

Not wrong, since the OWASP testing guidance accepts it. It just confirms existence, so decide whether that matters for your data.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.