ManagedQA PartnersSee plans

Methods · 2026-08-22 · 2 min read

The two-user test

The only proof that an access policy works is a foreign read that returns nothing. Here is the test, how to automate it per table, and why reading the policy is not enough.

Checklist item AC-02 has the plainest pass criterion on the list: user B receives zero rows on select and a permission error on update and delete, for every table. It is also the item that finds the most critical issues.

The test

  1. Sign in as user A. Create one row in each table the release touched (or every table, monthly).
  2. Sign in as user B. Through the client API (the interface other software calls; tested directly, without the UI in between) with the publishable key, run select, update and delete against A's row.
  3. Record the result per table.

Pass is zero rows and two permission errors, per table. Anything else is a critical finding, because it is data exposure.

Why reading the policy is not enough

A policy can exist and be enabled and still be wrong. The catalogue has a pattern for it: a condition that evaluates true for everyone, added because it made a failing query pass. CVE-2025-48757 was filed as an insufficient policy on generated sites, not a missing one. (Source: NIST National Vulnerability Database, 2025-05-30 · verified 2026-09-21) Bolt's own database security settings warn about an "RLS (row-level security: database rules that decide which rows each signed-in user may read or write) Policy Always True" case for the same reason.

Reading a policy tells you what the author intended. Running the test tells you what the database does.

Automating it

The test is a fixture and a loop: create user A and B in the test project, iterate over the table list from the catalog, insert as A, attempt as B, assert. In the suite we maintain it runs on every release in CI (the pipeline that builds and tests every change before it can be merged or deployed) and takes seconds. On Firebase it runs against collections through the rules unit-testing library in the emulator, and against the deployed project on release.

The one thing to keep in mind: the table list has to come from the database, not from the code. A table the code does not mention is still exposed.

The companion items

AC-01 queries the catalog for the RLS flag, which catches the missing-policy case before the two-user test (sign in as one user, create a row, then try to read or change it as another user; pass is nothing comes back) runs. AC-03 is the same idea for endpoints that take an id: call it as user B with A's id. AC-04 is the same idea for admin routes. Four items, one principle: prove isolation by attempting to break it, on every release.

The access control category has all six items with criteria.

More in methods

Blog · ManagedQA Partners