Mockly

glossary

Tenant ID Trusted from Client

Trusting tenant IDs from the client lets attackers impersonate other tenants. This page explains it in plain English, then goes deeper into how it works in Supabase/Postgres, what commonly goes wrong, and how to fix it without relying on fragile client-side rules.

What “Tenant ID Trusted from Client” means (plain English)

Never accept tenant_id from the client as proof of identity; derive it from auth claims or server state.

How Tenant ID Trusted from Client works in Supabase/Postgres (technical)

When queries or policies rely on client-provided tenant identifiers, attackers can pass other tenant IDs and bypass row-level guards. Tenant ID Trusted from Client usually appears when GRANT scope, RLS policy predicates, SECURITY DEFINER behavior, or request-context claims are misaligned. The durable control is to enforce authorization in SQL with explicit role checks, stable ownership predicates, and migration-tested policy coverage.

Attack paths & failure modes for Tenant ID Trusted from Client

  • Tenant ID Trusted from Client: direct API bypass: A multi-tenant view uses a tenant_id path param sent from the frontend.
  • Tenant ID Trusted from Client: migration drift regression: A feature lands with a new table or API that uses a tenant_id parameter without guardrails.
  • Tenant ID Trusted from Client: direct API bypass: Attackers changed the tenant_id value and the backend returned rows for other tenants.
  • Tenant ID Trusted from Client: migration drift regression: The client-supplied value allowed cross-tenant reads because the server accepted it as authoritative.
  • The configuration doesn’t match what the UI implies (direct API access bypasses the app).
  • Policies/grants drift over time and widen access without anyone noticing.
  • Fixes are applied without verification, leading to false confidence.

Why Tenant ID Trusted from Client matters for Supabase security

Cross-tenant data leaks happen as soon as the client controls the tenant dimension. If Tenant ID Trusted from Client remains unresolved, attackers can automate enumeration and unauthorized writes at API speed. Treat it as a production reliability risk as well as a data security risk, because incidents spread quickly once clients discover weak access boundaries.

Common Tenant ID Trusted from Client mistakes that lead to leaks

  • Using tenant_id query parameters as the source of truth.
  • Not binding tenant claims in policies.
  • Assuming tenant IDs remain constant without validation.
  • Tenant ID Trusted from Client: direct API bypass: Attackers changed the tenant_id value and the backend returned rows for other tenants.
  • Tenant ID Trusted from Client: migration drift regression: The client-supplied value allowed cross-tenant reads because the server accepted it as authoritative.

Where to look for Tenant ID Trusted from Client in Supabase

  • Your grants, policies, and any direct client access paths.
  • Storage and RPC settings (common blind spots).

How to detect Tenant ID Trusted from Client issues (signals + checks)

Use this as a quick checklist to validate your current state:

  • Try the same queries your frontend can run (anon/authenticated). If sensitive rows come back, you have exposure.
  • Verify RLS is enabled and (for sensitive tables) forced.
  • List policies and look for conditions that don’t bind rows to a user or tenant.
  • Audit grants to anon / authenticated on sensitive tables and functions.
  • Tenant ID Trusted from Client: direct API bypass: Never trust client-supplied tenant_id.
  • Tenant ID Trusted from Client: direct API bypass: Derive tenant membership from session claims.
  • Tenant ID Trusted from Client: direct API bypass: Policies should compare tenant claims explicitly.
  • Re-test after every migration that touches security-critical tables or functions.

How to fix Tenant ID Trusted from Client (backend-only + zero-policy posture)

Mockly’s safest default is backend-only access: the browser should not query tables, call RPC, or access Storage directly.

  1. Decide which operations must remain client-side (often: none for sensitive resources).
  2. Create server endpoints (API routes or server actions) for required reads/writes.
  3. Apply hardening SQL: enable+force RLS where relevant, remove broad policies, and revoke grants from client roles.
  4. Generate signed URLs for private Storage downloads on the server only.
  5. Re-run a scan and confirm the issue disappears.
  6. Add a regression check to your release process so drift doesn’t reintroduce exposure. Fixes that worked in linked incidents:
  • Tenant ID Trusted from Client: direct API bypass: Derive the tenant from the authenticated token or server context and ignore client-provided IDs.
  • Tenant ID Trusted from Client: migration drift regression: Require backend code to map the authenticated user to their tenant and include tenant checks in migration processes.

Verification checklist for Tenant ID Trusted from Client

  1. Attempt direct access using client credentials and confirm it fails.
  2. Apply a backend-only fix pattern and verify end-to-end behavior.
  3. Re-run a scan after changes and after the next migration.
  4. Tenant ID Trusted from Client: direct API bypass: Never trust client-supplied tenant_id.
  5. Tenant ID Trusted from Client: direct API bypass: Derive tenant membership from session claims.
  6. Tenant ID Trusted from Client: direct API bypass: Policies should compare tenant claims explicitly.
  7. Tenant ID Trusted from Client: direct API bypass: Test the API with other tenant IDs to confirm protections.
  8. Tenant ID Trusted from Client: migration drift regression: Migrations can add insecure tenant paths.

SQL sanity checks for Tenant ID Trusted from Client (optional, but high signal)

If you prefer evidence over intuition, run a small set of SQL checks after each fix.

The goal is not to memorize catalog tables — it’s to make sure the access boundary you intended is the one Postgres actually enforces:

  • Confirm RLS is enabled (and forced where appropriate) for tables tied to this term.
  • List policies and read them as plain language: who can do what, under what condition?
  • Audit grants for anon/authenticated and PUBLIC on the tables, views, and functions involved.
  • If Storage is involved: review bucket privacy and policies for listing/reads.
  • If RPC is involved: review EXECUTE grants for functions and whether privileged functions are server-only.

Pair these checks with a direct API access test using client credentials. When both agree, you can ship the fix with confidence.

Over time, keep a small “query pack” for the checks you trust and run it after every migration. That’s how you prevent quiet regressions.

Prevent Tenant ID Trusted from Client drift (so it doesn’t come back)

  • Add a repeatable checklist and re-run it after schema changes.
  • Prefer backend-only access for sensitive resources.
  • Keep one reusable verification test for “Tenant ID Trusted from Client: direct API bypass” and rerun it after every migration that touches this surface.
  • Keep one reusable verification test for “Tenant ID Trusted from Client: migration drift regression” and rerun it after every migration that touches this surface.

Rollout plan for Tenant ID Trusted from Client fixes (without breaking production)

Many hardening changes fail because teams revoke direct access first and only later discover missing backend paths.

Use this sequence to reduce both risk and outage pressure:

  1. Implement and verify the backend endpoint or server action before permission changes.
  2. Switch clients to that backend path behind a feature flag when possible.
  3. Then revoke direct client access (broad grants, permissive policies, public bucket reads, or broad EXECUTE).
  4. Run direct-access denial tests and confirm authorized backend flows still succeed.
  5. Re-scan after deployment and again after the next migration.

This turns security fixes into repeatable rollout mechanics instead of one-off emergency changes.

Incident breakdowns for Tenant ID Trusted from Client (real scenarios)

Tenant ID Trusted from Client: direct API bypass

Scenario: A multi-tenant view uses a tenant_id path param sent from the frontend.

What failed: Attackers changed the tenant_id value and the backend returned rows for other tenants.

What fixed it: Derive the tenant from the authenticated token or server context and ignore client-provided IDs.

Why the fix worked: The server now enforces the authoritative tenant, so swapping values no longer works.

Key takeaways:

  • Never trust client-supplied tenant_id.
  • Derive tenant membership from session claims.
  • Policies should compare tenant claims explicitly.
  • Test the API with other tenant IDs to confirm protections.

Read full example: Tenant ID Trusted from Client: direct API bypass

Tenant ID Trusted from Client: migration drift regression

Scenario: A feature lands with a new table or API that uses a tenant_id parameter without guardrails.

What failed: The client-supplied value allowed cross-tenant reads because the server accepted it as authoritative.

What fixed it: Require backend code to map the authenticated user to their tenant and include tenant checks in migration processes.

Why the fix worked: The server uses an authoritative tenant source so client tampering is rejected.

Key takeaways:

  • Migrations can add insecure tenant paths.
  • CI should enforce tenant validation.
  • Document where tenant identity comes from.
  • Monitor direct calls for unusual tenant swaps.

Read full example: Tenant ID Trusted from Client: migration drift regression

Real-world examples of Tenant ID Trusted from Client (and why they work)

Related terms

  • Insecure Direct Object References (IDOR) → /glossary/insecure-direct-object-references
  • Missing WITH CHECK Policy → /glossary/missing-with-check-policy

FAQ

Is Tenant ID Trusted from Client enough to secure my Supabase app?

It’s necessary, but not sufficient. You also need correct grants, secure Storage/RPC settings, and a backend-only access model for sensitive operations.

What’s the quickest way to reduce risk with Tenant ID Trusted from Client?

Remove direct client access to sensitive resources, enable/force RLS where appropriate, and verify via a repeatable checklist that anon/authenticated cannot query what they shouldn’t.

How do I verify the fix is real (not just a UI change)?

Attempt direct API queries using the same client credentials your app ships. If the database denies access (401/403) and your backend endpoints still work, your fix is effective.

Next step

Want a quick exposure report for your own project? Run a scan in Mockly to find public tables, storage buckets, and RPC functions — then apply fixes with verification steps.

Explore related pages

parent

Glossary

/glossary

sibling

Insecure Direct Object References (IDOR)

/glossary/insecure-direct-object-references

sibling

Missing WITH CHECK Policy

/glossary/missing-with-check-policy

cross

Lock down a public table (backend-only access)

/templates/access-control/lock-down-public-table

cross

Remove over-permissive RLS policies (adopt deny-by-default)

/templates/access-control/remove-over-permissive-policies

cross

Pricing

/pricing