Enabled but permissive
Row level security is on, and the policy is effectively USING (true). The dashboard shows green, the table is fully readable, and nothing distinguishes this from correct configuration without reading the policy text.
Modern applications expose the database directly to the browser. Any control that lives only in the interface is bypassed by calling the API instead — and almost nobody tests whether theirs holds.
A database security review examines who can read and modify which records, as enforced by the database itself rather than by application code or the user interface. It is distinct from a penetration test, which typically probes the perimeter and the application surface. The review enumerates every table holding user or tenant data and confirms that row level security is enabled with an explicit default-deny policy; it inspects roles and permissions against the principle of least privilege; it checks object storage permissions and signed URL usage; and critically, it verifies policies by direct query rather than by reading them. Verification means authenticating as one tenant and requesting another tenant's data through the API. Zero rows returned is the only passing result.
The application behaves correctly. No error is logged. The exposure is visible only to someone who thinks to ask the database rather than the interface.
Row level security is on, and the policy is effectively USING (true). The dashboard shows green, the table is fully readable, and nothing distinguishes this from correct configuration without reading the policy text.
Most tables were secured. One was added later for a small feature and never reviewed — and it joins to everything else, which is how a minor omission becomes a full disclosure.
Uploads sit behind an application route, so the bucket itself was never restricted. The objects are directly addressable, permanently public, and nothing in the interface suggests it.
Nothing is sampled. Every table in every schema is enumerated, because the one that was missed is the one that matters.
Every table in every schema, with row level security status and the actual policy text recorded — not a sample, and not what the dashboard summarises.
Live queries authenticated as one tenant against another tenant's data, run through the API exactly as an attacker would. Any returned row is a Critical finding.
Permissions assessed against least privilege, plus object storage bucket rules, public access settings and signed URL handling for private objects.
Corrected policies written out and ready to apply, each paired with the verification query that proves the fix rather than asserting it.
Reading a policy establishes intent. Only executing a query establishes effect — and the two disagree more often than anyone expects.
Verify domain ownership and receive read-only credentials scoped to the review.
Every table in every schema, with RLS status recorded. Sampling is not sufficient.
Inspect the actual policy text. A policy that exists is not a policy that restricts.
Authenticate as one tenant, request another's data through the API. Zero rows is the only pass.
Provide corrected policy text and the verification query that demonstrates each fix.
Why policies are verified by query and never by inspection. A policy can be present, syntactically valid, visible in a dashboard, and still permit everything. Reading policy text establishes intent; only executing a query establishes effect. Rule CYB-02 therefore requires verification by authenticating as one tenant and requesting another tenant's data directly through the API, with any returned row treated as a Critical finding. This distinction matters because the failure mode is entirely silent — the application behaves correctly, no error is logged, and the exposure is visible only to someone who thinks to ask the database rather than the interface.
Source: The Qawex Standard v1.0, rules CYB-01 and CYB-02 · Read the Cyber rulesIt requires credentials, database expertise and a different mindset from perimeter testing, and it sits between the traditional boundaries of security firms and development agencies. Meanwhile hundreds of thousands of applications now expose a database directly to the browser, which makes the gap larger every month rather than smaller.
Read-only credentials scoped to the review, plus verified domain ownership. We do not need write access, we do not copy production data, and credentials are revoked at the end of the engagement. Where a data sample is genuinely necessary for analysis, it is agreed in writing beforehand.
Yes. Row level security is a PostgreSQL feature, and the same review applies to any PostgreSQL database. The exposure is more acute where a public API key reaches the browser, but the underlying question — whether access is enforced at the database or only in the interface — applies to every architecture.
You are told immediately and privately, with corrected policy text and the verification query attached, before anything is written into a report. Critical findings are communicated the same day. Nothing is published, and that holds regardless of whether you become a client.
Yes, and the Standard is public so you can. Enumerate every table, confirm row level security is enabled with a default-deny policy, then authenticate as one tenant and query another's data through the API. If any row returns, you have a Critical finding. We are useful for the depth and the second pair of eyes, not because the method is secret.
The review enumerates every table, reads every policy, and verifies by live cross-tenant query. Findings are private by default and are yours to keep.