AI Tool Database-Read Privilege Scoping Automation: A Blocklist Stopped 1 Table Out of 6,608

A list of forbidden names is only as strong as its own pattern-matching
A blocklist feels like a reasonable first line of defense against an AI tool reading data it should not see: name the sensitive tables, check the query text against that list, refuse a match. The weakness is structural, not incidental — the check only works if its own text-matching logic is correct for every real table name it will ever face, and a single silent failure in that matching logic (a word-boundary pattern that does not account for how compound names are actually built) turns an intended blocklist into a list that blocks almost nothing, with no visible symptom until someone measures it directly against the real schema.
How the underlying problem shows up before you fix it
A database function meant to run with restricted, read-only access is instead owned by a role that carries the privilege to bypass row-level security entirely, because `SECURITY DEFINER` functions execute with their OWNER's privileges, not the caller's.
A safeguard is built as a list of forbidden text patterns rather than a list of permitted actions, so a single gap in the pattern — not a gap in the intent — silently exposes everything the pattern fails to catch.
A word-boundary check assumes a boundary exists between two words joined by an underscore, when the underscore itself counts as part of the "word" to the regex engine, and a name like `synapse_widget_sites` sails past a rule written to catch `widget_sites`.
The two or three cases where the blocklist appeared to work were shown, on closer inspection, to be catching queries by their COLUMN name rather than their table name — meaning a trivially rewritten query (selecting a full row instead of one named column) reads the exact same data and passes the same check.
A regression test suite exercises the happy path of a safeguard extensively, but has no case that actively tries to defeat the safeguard's own logic — so a defect in the defense mechanism itself can survive a fully green test suite indefinitely.
How the gap was measured, and why the fix changes ownership instead of the list
Auditing the read tool's own database function directly — not the parameter the application code happened to pass it, but the actual SQL the function ran — showed it was owned by the database's superuser-equivalent role, which carries the ability to bypass row-level security on every table in the schema. Because the function was declared `SECURITY DEFINER`, it executed with that owner's full privileges on every call, regardless of who invoked it or what row-level policies existed on the tables involved. The only thing standing between a caller and any row in the schema was a list of table names the query text was checked against before running.
Measuring that list against the real schema showed it barely worked at all: of 6,608 tables in the public schema, the blocklist's pattern stopped exactly one. The root cause was a word-boundary regex written as if table names were matched by substring, when in practice the boundary anchor treats an underscore as part of the same "word" — so a rule meant to catch a table literally named `widget_sites` never matched the real table `synapse_widget_sites`, and by extension never matched any of the platform's actual table names, which are built with a system-name prefix by convention. The handful of cases where the list appeared to be working were traced to catching a query by its COLUMN name rather than its table name — a distinction that a minimally rewritten query (reading every column instead of one) erased entirely, with the same result reaching the caller either way.
Rather than write a more careful pattern — which would still be one silent edge case away from the same class of failure — the fix changes the more fundamental fact underneath the whole mechanism: WHO the function runs as. Ownership moves from the privileged role to a new, dedicated role created specifically for this purpose: it cannot log in on its own, it does not carry the row-level-security bypass privilege, and it has not been granted `SELECT` on a single table — confirmed directly against the schema, where zero of the 6,608 tables grant `SELECT` to the general `PUBLIC` role. Because `SECURITY DEFINER` privilege comes entirely from the function's owner, changing the owner changes what the function is capable of reading, independent of anything the query text says. A regex can be rewritten around by a differently-worded query; a role with no grants cannot read a table no matter how the query asking for it is phrased.
Three further checks were added on top of the ownership change, each a positive rule rather than a negative one: the caller's arguments must carry an organization identifier that matches the tool's own configured organization; a tool that is scoped to a specific tenant requires the query to reference that exact tenant, not merely one from the same organization; and any query with a `FROM` clause must explicitly reference the organization filter in its `WHERE` condition. That last, specific check exists because measuring against real production traffic surfaced one more real gap: a caller from the SAME organization as a tool could pass a NEIGHBORING tenant's identifier and successfully read that tenant's own rows through a tool registered for a different tenant entirely — a narrower, but real, version of the same underlying problem. Separately, while building the harness to prove the FROM-clause check actually worked, the audit found the check's own regular expression had a single corrupted byte in place of an escape sequence — it compiled, the typecheck passed, and the existing test suite passed, because no test had ever actually exercised the refusal path the broken regex was supposed to trigger.
What is actually built today
The AI-facing SQL read tool's database function is owned by a dedicated, no-login role with zero table grants of its own and no row-level-security bypass privilege — the privilege boundary comes from ownership, not from pattern-matching the query text.
A caller's arguments must carry an organization identifier matching the tool's own configured organization before any query runs.
A tool scoped to a specific tenant requires the query to reference that exact tenant — a caller from the same organization cannot substitute a neighboring tenant's identifier and read their rows.
Any query with a FROM clause must explicitly reference the organization filter in its own WHERE condition, verified by a corrected regular expression (the prior version had a corrupted escape sequence that silently never matched anything).
One AI-registered tool pointing at a table that never existed in production, and a query with an organization/tenant hardcoded as a literal value rather than parameterized, were both found and corrected in the same pass.
The service's own header comment, which had claimed a one-role-per-tenant model that was not actually true, was corrected to describe the real, single-role design accurately.
A rule for "widget_sites" that never once matched "synapse_widget_sites" (illustrative framing of the actual measured finding)
A blocklist entry is written to stop a query from reading a sensitive table, using a rule meant to catch that exact table name wherever it appears. In production, every real table carries a system-name prefix as a naming convention — so the rule, written for the bare name, silently never fires against a single real table in the schema, and the safeguard exists only on paper. After the fix, the question of which table gets read is no longer decided by matching a name pattern at all — it is decided by whether the function's own owner has been granted permission to read that table in the first place, which for this function is now permanently zero tables.
What changes operationally
The AI-facing SQL read tool can no longer read any table through a privilege inherited from its owner — its access is bounded by a role with zero grants of its own, closing a gap where a blocklist measured at stopping 1 of 6,608 tables had been the only defense against reading another organization's encrypted provider keys.
When this is not the right fit
This automation governs which tables a specific AI-facing read tool's underlying function can access at the database privilege layer — it does not replace an organization's own review of which specific tools and data categories it chooses to make available to its AI agents.
A better blocklist vs. a role with nothing to give away
The instinctive fix for a blocklist that missed a table is usually another blocklist entry — which only ever closes the specific gap that was just found, leaving the same class of failure open for the next table name shape nobody has thought of yet. Centriu's fix removes the entire category of failure by making the question moot: a role with no table grants has nothing a clever query can extract, regardless of how the query is worded, aliased, or restructured.
Related systems
Main system: Centriu Synapse. Complementary when relevant: Centriu Axis.
What it does NOT do
- Does not claim to have found or fixed every possible database-privilege gap across the platform — this fix closes the specific, measured exposure found in this audit of the SQL read tool.
- Does not remove the organization- and tenant-scoping checks that existed before — it adds a privilege-layer boundary underneath them, and keeps the query-level checks as an additional, independent layer.
- Does not change what a human operator with direct, authorized database access can see — this fix governs the AI-facing tool's own function, not administrative database access in general.
- Does not retroactively audit or report on any historical query the tool ran before this fix shipped.
- Does not grant the new restricted role any table access — by design, it is not meant to ever need one, since privilege comes from what it lacks, not what it has.
- Does not replace an organization's own decision about which specific AI tools and data categories it enables for its own agents.
Security and governance
The read tool's underlying function now executes as a role with zero table grants and no row-level-security bypass privilege, with organization and tenant identity checked positively before any query runs. Any business or client data referenced remains subject to Brazil's LGPD (Law No. 13,709/2018). Full detail on access control lives at /governanca and /iso.
Pricing and contracting
Available by monthly subscription, with tiered plans. Values and terms come from the official pricing table at /precos (Centriu's central source — never restated here).
Frequently asked questions
Why did the table-name blocklist only stop 1 of 6,608 tables?
Its word-boundary matching pattern treated an underscore as part of the same word, so a rule written for a bare table name never matched the real tables, which all carry a system-name prefix by convention.
What changed instead of writing a better blocklist?
The function's OWNER changed, from a role with database-wide bypass privilege to a dedicated role with zero table grants of its own — privilege now comes from ownership, not from matching query text.
Could a caller read a different tenant's data within the same organization?
That was a real, separately measured gap — fixed by requiring a tenant-scoped tool's query to reference that exact tenant, not merely a tenant from the same organization.
How was a broken safeguard passing a green test suite?
The check's own regular expression had a corrupted escape sequence that compiled and typechecked cleanly but never actually matched anything — and no existing test exercised the refusal path it was supposed to trigger.
Does this affect what a human administrator can access directly?
No — this fix governs the AI-facing read tool's own database function specifically, not direct, authorized administrative database access.
What does Centriu Synapse cost?
It is sold by subscription with a published starting price — exact current values are on the central pricing page.
See how Centriu Synapse scopes AI tool database access by privilege, not by pattern
Reach our commercial team directly, or leave your details below — we'll follow up with guidance for your case.
