access control reviewsupabase securityfirebase securityrls testingapp security audit

Your Access Control Review Playbook for Supabase & Firebase

Run a complete access control review for your Supabase, Firebase, or mobile app. This practical playbook covers RLS fuzzing, SQL queries, and CI/CD automation.

Published June 2, 2026 · Updated June 2, 2026

Your Access Control Review Playbook for Supabase & Firebase

You shipped a feature late on Friday. It looked harmless. A new dashboard filter, a helper RPC, maybe a relaxed Firebase rule to get mobile sync working. On Monday, someone notices that one signed-in user can see another customer's records, or a contractor account can still hit an internal endpoint months after the engagement ended.

That's what an access control review looks like in modern app teams. Not a spreadsheet exercise. Not a box-ticking IAM ceremony. It's the work of proving that your app only exposes the data and actions each identity should have, across your database, storage, functions, tokens, and automation.

If you're building on Supabase or Firebase, most traditional guidance is too generic to help. It assumes central directory groups, stable enterprise roles, and a clean separation between app logic and infrastructure. Your stack probably doesn't look like that. You've got Row Level Security, JWT claims, edge functions, service roles, storage buckets, CI secrets, preview environments, and a lot of business logic living close to the data layer.

Why Your App's Permissions Are Probably Broken

Most startups don't break permissions with one spectacular mistake. They break them through small decisions that seem reasonable in isolation.

A developer adds a broad read rule during testing and forgets to tighten it. An RPC is created with higher privileges because the client needed one extra write path. A Firebase rule is copied from a sample app and never revisited after the data model changed. A service key ends up in the wrong environment variable scope. None of that feels dramatic while you're shipping.

Why generic audit advice misses the real problem

Traditional access reviews focus on user directories, group membership, and manager approvals. That matters in some environments, but it misses the places where modern app teams usually leak data.

In Supabase, risk often sits in RLS policies, security definer functions, and storage policies. In Firebase, it sits in Security Rules, document path assumptions, and server-side code that bypasses client restrictions. If you only review who belongs to an admin group, you haven't reviewed the app. You've reviewed one thin layer of it.

What tends to fail in practice:

  • Policy drift where the code and the permission model no longer match
  • Token trust without verification where claims are assumed to be correct everywhere
  • Backdoor write paths through functions, jobs, or internal tooling
  • Forgotten identities such as service accounts, API consumers, and ex-contractors

Practical rule: If your team can't explain who can read, write, update, or delete each sensitive dataset without opening three different consoles, your access model is already too opaque.

Why this is a board-level issue in the UK

This isn't just engineering hygiene. In the UK, access control review became materially more important after the Data Protection Act 2018 and UK GDPR came into force, because organisations must prove they have appropriate measures to protect personal data. Enforcement shows the cost of getting this wrong. The ICO fined Capita Financial Administrators £14 million in 2023 and British Airways £20 million in 2022 for security control failures, illustrating how weak oversight can lead to serious penalties, as outlined in this guide to understanding data security regulations and in the cited review of UK access review enforcement examples.

For a startup, the practical takeaway is simple. If your app stores personal data, your permission model is part of compliance evidence. You need to know what the rules are, whether they work, and who approved exceptions.

Scoping Your Review and Adopting Least Privilege

A useful access control review starts with scope. If you review only human users, you'll miss machine access. If you review only application roles, you'll miss direct database paths. If you review only production tables, you'll miss storage buckets and background jobs moving the same data elsewhere.

A flowchart diagram illustrating the steps for defining the scope of an access control review process.

Start with assets, not org charts

List the things that expose or move data in your stack. For Supabase and Firebase teams, that usually means more than the auth provider.

Review these components first:

  • Core data stores. Tables, collections, views, and any derived datasets that contain customer, employee, financial, or operational data.
  • Policy layers. Supabase RLS policies, Firebase Security Rules, custom claims, and any middleware checks that shape access.
  • Execution paths. RPCs, edge functions, Cloud Functions, scheduled jobs, admin scripts, and import/export tooling.
  • File access. Storage buckets, object paths, signed URL flows, and upload handlers.
  • Privileged identities. Service accounts, API keys, server roles, CI tokens, and break-glass credentials.
  • Third-party access. Analytics tools, support tooling, CRM syncs, agencies, and contractors with standing access.

Many teams find their first surprise with this realization: the broadest access often isn't assigned to a person. It sits with tooling.

Translate least privilege into app-specific checks

The National Cyber Security Centre recommends least privilege, privileged access review, and limiting admin rights so users keep only the access essential for their role. UK guidance also expects organisations to evidence who has access, why, and when it was last reviewed, as summarised in this overview of regular access reviews and least privilege under UK guidance.

For modern apps, least privilege has to be translated into technical questions:

  • Can a normal signed-in user read only their own rows or documents?
  • Can support staff view data without changing it?
  • Can a background job write only to the tables it needs?
  • Can a contractor account access production at all?
  • Can an RPC escalate privileges beyond the caller's intended scope?
  • Can uploaded files be listed or fetched outside the expected tenant boundary?

Least privilege in a BaaS stack isn't about making roles look tidy. It's about reducing every identity to the smallest useful set of reads, writes, and execution paths.

Build a review sheet your team can actually use

A lightweight sheet beats a perfect but unused framework. For each asset, capture:

| Item | What to record | |---|---| | Data asset | Table, collection, bucket, function, or integration | | Owner | Named engineer or team | | Allowed identities | Human and non-human | | Allowed actions | Read, write, update, delete, execute | | Justification | Business reason for access | | Enforcement point | RLS, Firebase Rule, server check, IAM, code path | | Last review | Date and reviewer | | Required fix | Remove, narrow, document, or test |

If your roles are still fuzzy, tighten them before the review. A short primer on role-based access control helps when you need to distinguish “support can inspect billing status” from “support can export all billing records”.

The Manual and Automated Check Hybrid

The first serious access control review shouldn't be fully manual, and it shouldn't be fully automated either. Manual review finds obvious mistakes fast. Automation catches the boring, repeatable issues that humans skip once they're tired.

Manual checks that find the ugly stuff quickly

Start with a console walk-through and code review. You're looking for the highest-risk failures, not elegance.

Check for these first:

  • Disabled or missing policy enforcement. In Supabase, look for tables with RLS off, or enabled but effectively bypassed through broad policies.
  • Catch-all authenticated access. Rules that allow any signed-in user to read or write sensitive data usually survive because they were once convenient.
  • Overpowered functions. Review RPCs and server functions for privileged execution context, especially anything that updates ownership, roles, or billing state.
  • Storage overexposure. Buckets often have weaker controls than the main database, especially for profile exports, invoices, or internal uploads.
  • Role collisions. A user who is both “member” and “admin” through different paths may pass checks you didn't intend.
  • Dead accounts with live access. Former staff, stale contractor users, abandoned preview environments, and forgotten service principals.

A good manual review is opinionated. If a rule is hard to explain, treat that as a defect until proven otherwise.

Automation gives you repeatability

For UK organisations, the strongest benchmark is compliance-driven. Access reviews should map to documented roles, least-privilege checks, and auditable remediation. Guidance also recommends automating exports and policy comparisons to reduce manual error and speed up follow-up, as described in this review of automated evidence and role-based access review practice.

That matters because startup teams rarely fail from lack of intent. They fail from inconsistency. The fix is to turn recurring questions into queries and checks.

Here's a simple table you can adapt for Supabase.

Sample Supabase Audit Queries

| Query Purpose | Sample SQL Snippet | |---|---| | Find tables where RLS is disabled | select schemaname, tablename, rowsecurity from pg_tables where schemaname = 'public' and rowsecurity = false; | | List policies by table | select schemaname, tablename, policyname, permissive, roles, cmd, qual, with_check from pg_policies where schemaname = 'public' order by tablename, policyname; | | Spot tables with RLS enabled but no visible policies | select t.tablename from pg_tables t left join pg_policies p on t.schemaname = p.schemaname and t.tablename = p.tablename where t.schemaname = 'public' and t.rowsecurity = true group by t.tablename having count(p.policyname) = 0; | | Review grants on tables | select table_schema, table_name, grantee, privilege_type from information_schema.role_table_grants where table_schema = 'public' order by table_name, grantee; | | Find security definer functions | select n.nspname as schema_name, p.proname as function_name, p.prosecdef as security_definer from pg_proc p join pg_namespace n on p.pronamespace = n.oid where n.nspname not in ('pg_catalog', 'information_schema') and p.prosecdef = true; | | Inventory functions exposed outside system schemas | select routine_schema, routine_name from information_schema.routines where routine_schema not in ('pg_catalog', 'information_schema') order by routine_schema, routine_name; |

What these queries won't tell you

They won't prove the rules are correct. They only tell you where to look.

A table can have RLS enabled and still leak because the condition is too broad. A function can look legitimate but accept an object ID that lets one tenant operate on another tenant's data. Grants can be clean while an edge function still bypasses them.

If the result of your audit is just a list of policies, you've inventoried controls. You haven't validated them.

Use automation to generate a review pack every time. Export policies, grants, functions, and service identities into one place. Then compare changes across releases. That gives you evidence, and it also makes bad diffs obvious.

Proving Leaks with RLS Fuzzing and Logic Testing

Static review catches misconfigurations. It doesn't catch all permission flaws. The nastiest leaks happen when the policy looks sensible but breaks under real application behaviour.

That's why serious access control review has to include logic testing. Not “does the rule exist?” but “can a user do something they should never be able to do?”

A five-step process diagram illustrating the workflow for uncovering hidden access control leaks in systems.

What RLS fuzzing actually means

In a Supabase context, RLS fuzzing means authenticating as different users and systematically attempting reads and writes against records that should be out of bounds. You vary tenant IDs, ownership fields, status flags, path parameters, nested relations, and function inputs. Then you observe the outcome.

You're trying to answer questions like:

  • Can User A read User B's rows by changing a filter?
  • Can a user insert a row that assigns ownership to someone else?
  • Can a client call an RPC that updates records outside its tenant?
  • Can a “read-only” role trigger a write through a helper function?
  • Can a signed URL or storage path reveal another customer's files?

This kind of testing gives you hard evidence. If an unauthorised request succeeds, the issue is no longer theoretical.

A simple test pattern

The exact implementation varies by stack, but the pattern is consistent.

  1. Create two ordinary test users in different tenants or ownership contexts.
  2. Seed records for each user plus edge cases like null ownership, archived status, or shared resources.
  3. Authenticate as User A.
  4. Attempt reads, inserts, updates, and deletes against User B's records.
  5. Repeat through direct table access, RPCs, storage paths, and app endpoints.

A conceptual pseudo-test looks like this:

| Test goal | Example idea | |---|---| | Cross-user read | User A requests records where owner_id = user_b_id | | Cross-user update | User A updates User B's profile or order status | | Ownership forgery | User A inserts a row with owner_id = user_b_id | | Tenant breakout | User A calls a function with another tenant identifier | | Storage breakout | User A requests or lists files in another user's path |

The failures static review misses

The biggest category is correct-looking logic with wrong assumptions.

Common examples:

  • A policy trusts a JWT claim that isn't set in every auth flow.
  • A helper function runs with privileged rights and skips ownership checks.
  • An update policy checks the old row but not the new values.
  • A Firebase rule validates path access but ignores a field that changes visibility.
  • A support tool uses server credentials and exposes unfiltered results to the frontend.

When you test offensively, these flaws stop hiding behind clean-looking policy code. If you need a parallel mindset, this overview of API penetration testing is a useful way to think about attacking authorisation boundaries instead of just reviewing them.

Static analysis tells you what the policy says. Fuzzing tells you what the system does.

Make proof easy to act on

Don't file findings as “policy may be weak”. File them as demonstrated impact.

Use a finding format like this:

  • Identity used: ordinary authenticated user
  • Action attempted: update another tenant's invoice status through RPC
  • Expected result: denied
  • Observed result: succeeded
  • Affected component: function name, table, rule, or endpoint
  • Likely cause: missing ownership check, broad claim trust, unintended privileged execution
  • Fix direction: tighten policy, add server-side validation, remove security definer, add regression test

Engineers fix what they can reproduce. A passing or failing test is far more persuasive than a vague warning.

Automating Your Audit in CI/CD and Prioritising Fixes

A one-off review helps. A pipeline-enforced review changes team behaviour.

The goal isn't to turn every pull request into a compliance workshop. The goal is to stop permission regressions before they hit production, and to make the highest-risk findings impossible to ignore.

A six-step infographic illustrating a continuous access control security workflow within a CI/CD development pipeline environment.

Put permission checks where code already flows

Your pipeline should fail or warn on access-control changes the same way it handles broken tests.

In practice, that means:

  • Schema diff checks for new tables, views, functions, and grants
  • Policy snapshots so RLS or Firebase rule changes are visible in review
  • Automated logic tests against ephemeral environments
  • Secret and service credential checks for client bundles and mobile builds
  • Release gates for privileged changes such as new admin roles or public bucket exposure

If your team already uses GitHub Actions or GitLab CI, this is a natural extension of CI/CD security testing. Treat access control as release quality, not post-release cleanup.

Prioritise with a simple matrix

Not every finding deserves the same urgency. Teams get stuck when every issue is labelled critical.

Use two axes:

| Impact | Questions to ask | |---|---| | Data sensitivity | Does this expose personal, financial, operational, or internal data? | | Access scope | Can one user affect only themselves, one tenant, or many tenants? |

Then add a practical modifier for exploitability:

  • Easy from the client
  • Requires authenticated access
  • Requires internal tooling or a privileged token

This gives you a workable ordering:

  • Fix now. Cross-tenant read/write, public exposure, broad service account misuse, privileged function bypasses.
  • Fix next sprint. Role collisions, stale contractor access, over-broad support access, weak storage segmentation.
  • Schedule and monitor. Noisy but lower-impact findings, legacy role clean-up, documentation gaps.

Don't ignore non-human identities

A large share of real permission risk sits outside employee accounts. Service accounts and API keys often have broad, long-lived access because they were created to “just make the integration work”.

That gap matters. The UK's Cyber Security Breaches Survey 2024 found that 50% of businesses and 32% of charities reported a cyber security breach or attack in the previous 12 months, reinforcing the need to review the full identity environment, including non-human identities, as highlighted in this analysis of machine identities and access review scope.

Review these with the same scrutiny as users:

  • Service accounts used by backend jobs and integrations
  • API keys embedded in mobile apps, scripts, or partner integrations
  • CI tokens with deployment or database access
  • Shared technical accounts used by support, data, or agency staff

A service account with permanent broad access is still an identity problem. It just doesn't show up in your org chart.

Turn findings into engineering work

Every finding should end in one of four actions:

  1. Remove access.
  2. Narrow access.
  3. Add compensating checks and tests.
  4. Accept temporarily with named owner and expiry date.

That last one matters. Startups do need exceptions. The mistake is leaving them ownerless.

Establishing a Continuous Monitoring Rhythm

The teams that stay secure aren't the ones with the most polished audit deck. They're the ones with a repeatable rhythm.

For a startup, that rhythm doesn't need to be heavy. It needs to be hard to skip. A practical cadence is to review high-risk permissions on a regular schedule, run automated checks on every meaningful schema or rule change, and re-test previously fixed leaks so they don't creep back in through new features.

A sustainable operating pattern

Keep the recurring process small enough that engineering will do it:

  • Release-time checks. Run automated policy, function, and logic tests on every release candidate.
  • Regular review windows. Review privileged roles, service accounts, contractor access, and sensitive data paths on a fixed cadence.
  • Event-driven review. Trigger an immediate review when someone creates a new admin path, adds a new integration, changes tenant logic, or introduces a new data store.
  • Regression tracking. Keep a list of prior access bugs and re-run those tests continuously.

The point isn't bureaucracy. It's memory. Teams forget. Pipelines don't.

What to alert on

You don't need alerts for every permission change. You need alerts for changes that widen blast radius.

Good candidates include:

  • New privileged roles or claims
  • New security definer functions
  • Public storage or relaxed bucket rules
  • New service accounts
  • Changes to tenant scoping logic
  • Removal or broadening of existing RLS or Firebase rules

Make someone own each alert class. An alert with no owner is just background noise.

Good access control review becomes routine when the system tells the right people about risky change before customers do.

The lasting mindset shift is this. Permissions are product logic. If your app decides who can see, change, or export data, then access control isn't a separate compliance task. It's part of how the product works. Treat it with the same discipline you already apply to migrations, payments, and production incidents.


If you want a faster way to validate Supabase, Firebase, or mobile app permissions without building the whole testing harness yourself, AuditYour.App helps teams find exposed RLS rules, unsafe RPCs, leaked keys, and real read or write leaks through logic fuzzing. It's a practical option when you need a one-off audit, continuous monitoring, or a second pair of eyes on a modern app stack.

Scan your app for this vulnerability

AuditYourApp automatically detects security misconfigurations in Supabase and Firebase projects. Get actionable remediation in minutes.

Run Free Scan