Skip to content
Centriu
Centriu Vértice

Member Write-Surface Verified Reduction Automation: Measure Before You Claim the Number

An earlier security pass on Centriu Vértice's database had closed direct write access on 52 objects belonging to one specific data family, and left an explicit, honest note behind: 827 other `vertice_*` objects still carried the same underlying platform default — direct write privilege granted to both the anonymous and the authenticated database role — with their actual, real-world reachability not yet measured. Rather than close all 827 on the strength of that number alone, the actual surface was measured first: 414 had row-level security turned on with zero policies at all (the grant dies immediately, with nothing to evaluate), and 208 had a policy permitting only reads — 622 of the 827 were already completely inert. Of the 203 objects with a policy that genuinely permits writing, 137 require an administrative or moderator role a member does not hold, leaving 66 governed only by "this row belongs to you" — which collapse into 11 distinct policy expressions, not 203 separate risks. A full inventory of every file in the module that reads a member's own session token found exactly 2 real write call sites in the entire codebase — the same 2 an earlier migration had already identified and preserved. A mandatory adversarial test pass, run before any conclusion was written down, caught two findings this same investigation would otherwise have wrongly reported as newly-closed vulnerabilities: a status field a static reading of the access-control rules suggested a suspended member could rewrite back to active turned out to already be blocked by an existing database trigger, confirmed by the test actually attempting the exact write. What remained were 7 real, independently reproduced exposures — closed by revoking direct write privilege from every one of the 827 objects except the 2 confirmed-legitimate exceptions, in a single migration that verifies its own effect with 4 built-in checks rather than assuming success from the absence of an error.
827 objects, 2 real writers
2 false positives caught first
Database write-privilege audit screen
827 objects measured down to 2.

A number left open honestly is not the same as a number left unmeasured

Closing a security gap and then explicitly naming what is left, rather than declaring total victory, is the more honest and more useful way to hand off unfinished work — a residual noted with its actual scope stated plainly is something a future investigation can act on directly. The risk specific to that honesty is what happens next: a large residual count ("827 objects still carry this privilege") can be treated as if the count itself were the measure of danger, when the number that actually matters — how many of those objects are genuinely reachable by someone with no more than public credentials — has not yet been established at all. Closing all 827 objects identically, without first measuring which of them a real caller could actually exploit, would have been simpler to write and slower to verify than measuring first.

How the underlying problem shows up before you fix it

A residual security note from an earlier fix names a large count of objects sharing a privilege, without stating how many of them are actually reachable given the OTHER controls (like row-level security policies) already layered on top of that privilege.

A privilege that appears dangerous by name (direct write access, granted broadly) turns out, once measured, to be functionally inert for the large majority of cases where a companion control (a security policy denying every operation, or permitting only reads) already prevents it from ever being exercised.

A static reading of an access-control rule set (which roles hold which policy-permitted actions) suggests a specific write is possible, when a SEPARATE mechanism entirely — a database trigger, a check elsewhere in the write path — already blocks the exact same write in practice, meaning the rule-reading alone would produce a false positive if trusted without an actual, live attempt.

The genuinely small set of realistic exposures (here: 7, out of an initial count of 827) is only discoverable by combining a privilege-and-policy audit with an independent inventory of every actual code path that could exercise that privilege — measuring the grant alone, or the code alone, each miss half the picture.

A bulk privilege-revoking operation touches enough individual database objects, inside one transaction, that a routine, unrelated long-running query holding even one lock somewhere in that same set can turn an intended maintenance operation into a site-wide outage, if the operation has no explicit limit on how long it will wait for that lock.

How an alarming residual count became a measured, defensible fix

An earlier security migration on Centriu Vértice's database had closed direct write access, for the anonymous and authenticated database roles, on 52 objects belonging to one specific data family (member connections, business records, and opportunities) — and left behind an honest, explicit note: 827 OTHER `vertice_*` database objects still carried the exact same underlying privilege, a default the platform itself grants to every new table unless something specifically revokes it, with no measurement yet of how many of those 827 were actually reachable by a real, unauthorized caller.

Rather than close all 827 on the strength of that count alone, the follow-up work measured the real surface first, directly against the live production catalog. 414 of the 827 objects had row-level security enabled with zero policies defined on them at all — meaning any write attempt is refused before any policy logic even runs, because there is nothing to evaluate; the underlying grant is present but functionally dead. A further 208 had a policy that permits only reading, never writing — the same dead-on-arrival outcome for any write. That leaves 203 objects where a policy genuinely permits a write to succeed: 137 of those require an administrative, moderator, or specific staff role no ordinary member holds, and the remaining 66 are governed by some variant of "this specific row belongs to you" — a real, member-reachable write surface, but one that collapses, once the actual policy expressions are compared, into just 11 distinct patterns rather than 66 separate risks to reason about individually.

A second, independent measurement closed the loop: a full inventory of every file anywhere in the module that reads a member's own authenticated session token found 34 such files, of which exactly 3 perform any write at all, and one of those 3 performs no data write whatsoever (only a sign-in call). The other 2 write to precisely the 2 tables an earlier migration had already identified and deliberately preserved as legitimate member self-service writes. In the entire module, across every consumer of a member's own credential, there were exactly 2 real write call sites — a number small enough to reason about individually, arrived at only by combining the database-side policy audit with this separate, code-side inventory; either measurement alone would have missed real information the other one supplied.

Before writing any conclusion down, a mandatory adversarial test phase attempted each specific write a member's own credential might reach, directly against a real database, rather than reasoning about what SHOULD be possible from reading policy text alone. That step caught two specific findings this same investigation would otherwise have wrongly published as newly-discovered-and-fixed vulnerabilities: the most severe-looking one, a member's own status field appearing writable in a way that a suspended, expelled, or delinquent member could rewrite back to active status themselves (a status a separate function reads to authorize dozens of other actions across the product) — attempted directly against the real database, the write was rejected outright, blocked by an existing database trigger nobody had accounted for when reading the access rules alone. Without that mandatory live-attempt step, this fix would have claimed credit for closing a door that a completely different, pre-existing mechanism had already closed.

What survived the adversarial phase were 7 real, independently reproduced exposures: one member rewriting a bilateral fact the other party had recorded, a member pricing their own listed offer at a token amount, a revoked device reinstating its own trusted status, a consent record rewritten after the fact, a revoked session un-revoking itself, a member self-reporting their own onboarding as complete, and a forgeable terms-acceptance record with an arbitrary date and version. All 7 were closed the same way as the earlier 52: revoking the specific write privileges from every `vertice_*` object in the schema except the 2 objects confirmed, by the same investigation, to need them. The fix's own text is explicit about why a blanket revoke, rather than 64 individually hand-written and reviewed policy corrections, was the right shape: writing correct state-transition and column-immutability logic inside declarative policy expressions is fragile to write and harder to verify, and the underlying privilege was never a deliberate product decision in the first place — it came from the platform's own default access-control list, which grants broad privilege to every new table unless something specifically revokes it.

The revoke operation itself needed one more piece of production-specific care: removing a privilege from a database object requires an exclusive lock on that object for the duration of the operation, and the fix touches roughly 878 objects inside a single transaction — meaning every one of those locks is held simultaneously until the whole operation commits. The fix's own account names the exact failure mode a safeguard exists to prevent: if even one ordinary, unrelated query anywhere in the system is holding even a routine read lock on any one of those 878 objects at the moment the migration runs, the migration would wait for it — and every other request touching any of those objects would, in turn, queue up behind the migration itself, turning an intended, contained database change into a site-wide outage with no obvious link back to a single GRANT statement. A short, explicit wait limit specific to this operation means the migration fails fast and visibly instead, if that contention ever occurs, rather than silently waiting indefinitely while unrelated traffic backs up behind it.

The migration closes with its own proof, run automatically as part of applying it: a check confirming nothing in the schema still permits a direct write except the 2 named exceptions; a check confirming ordinary read access is untouched (so the row-level security layer still has something to actually govern); a check confirming the 2 legitimate member writes still function; and a check confirming the internal, elevated service credential the product itself relies on for real writes still has the access it needs. "The SQL executed without an error" was deliberately never treated as sufficient evidence that the fix did what it was meant to.

What is actually built today

Direct write privilege (insert, update, delete, truncate) for the anonymous and authenticated database roles is revoked from every `vertice_*` database object except 2 specific, confirmed-legitimate exceptions — closing 827 objects to 2, measured and verified in production.

The 622 objects that were already functionally inert (dead-on-arrival at row-level security, either with no policy at all or a read-only policy) are closed too, specifically to remove a latent trap: the underlying grant would silently reactivate the moment anyone later adds a permissive policy to one of them, with no separate step required.

A mandatory, live adversarial test phase — attempting each specific write against a real database rather than reasoning from policy text alone — runs before any finding is written down, specifically to catch and discard false positives a static reading would otherwise wrongly report as newly-fixed vulnerabilities.

The migration includes an explicit lock-wait limit for its own bulk-revoke operation, specifically so unrelated database contention causes the migration itself to fail fast and visibly rather than queuing the rest of the site's traffic behind an in-progress security fix.

The migration verifies its own effect with 4 built-in checks (no remaining write access outside the exceptions; read access intact; the 2 legitimate writes intact; the internal service credential's own write access intact) rather than treating the absence of a SQL error as proof of anything.

Two false alarms caught before publication, one real reinstatement path closed (illustrative framing of the actual measured findings)

Before this investigation, a static reading of Centriu Vértice's own access-control policies suggested a suspended, expelled, or delinquent member could rewrite their own profile's status field back to active — a function 35 separate policies elsewhere in the product rely on to decide what that member is currently allowed to do. Attempting that exact write against a real, live-configured database, as the mandatory adversarial test phase requires before any conclusion is accepted, found the write rejected outright by an existing database trigger — a real protection nobody had accounted for when reading the policy rules in isolation. Elsewhere in the same investigation, 7 different writes attempted the identical way DID succeed against the same real database, including a member setting their own listed price to a token amount and a revoked device reinstating its own trusted status — genuine exposures, closed by the same fix. The distinction between the false alarm and the real exposure was never visible from reading rules on paper; only an actual, live attempt against a real database told the two apart.

What changes operationally

Centriu Vértice's direct database write surface for unauthenticated and ordinary-authenticated credentials is reduced from 827 objects carrying the platform's own default write grant to exactly 2 confirmed-legitimate exceptions, following a measurement that combined a policy-reachability audit, a whole-module code inventory, and a mandatory live adversarial test phase — the last of which caught and discarded two findings that would otherwise have been wrongly published as newly-fixed vulnerabilities.

When this is not the right fit

This automation governs the internal database privilege-verification methodology behind Centriu Vértice's own access-control hardening — it does not change what a member can do through the product's own actual interface (the 2 preserved write paths cover every legitimate member self-service action this investigation found), and is specific to a platform whose default access-control list grants broad table privilege unless a project explicitly revokes it; a system with a more restrictive default would not accumulate this specific class of residual in the first place.

Closing a residual by its headline count vs. by its measured reachability

Closing all 827 objects identically, purely on the strength of an earlier honest disclosure naming that count, would have been the faster-sounding response and would have arrived at the same final database state — but without ever measuring which specific findings among them were real, it would also have risked publishing at least one false claim (the status-reinstatement path a static policy reading suggested was open) as a newly-discovered-and-fixed vulnerability, when a real trigger had already closed it. Measuring the actual reachable surface first, combining a database-side audit with a code-side inventory and a mandatory live adversarial test, takes longer to write up but produces a fix whose every claimed finding was independently, reproducibly verified against a real database before being reported as true.

Related systems

Main system: Centriu Vértice.

What it does NOT do

  • Does not change what a Centriu Vértice member can do through the product's own actual interface — every legitimate self-service write this investigation found (2 specific tables) continues to work exactly as before; only privilege that had no real consumer anywhere in the module was revoked.
  • Does not claim credit for closing the status-reinstatement path the initial policy reading suggested was open — that specific path was confirmed, by direct adversarial testing, to already be blocked by an existing database trigger, and is documented as a false positive the mandatory test phase caught rather than as a fix.
  • Does not close the platform's own default access-control list itself, which still grants broad privilege to any brand-new table unless a project explicitly revokes it — a newly-created table starts open again, and closing the default itself is documented as a separate, not-yet-made platform-level decision.
  • Does not retroactively identify whether any of the 7 real exposures was actually exploited by a real, unauthorized party before this fix shipped — the production data affected by the exposures showed zero rows created in the relevant tables at measurement time, and a team with a broader historical concern would need its own separate audit-log review.
  • Does not overlap with the other two fixes shipped in the same commit (authentication failure classification, and the AI-agent tool access surface) — both are covered on their own companion pages and are architecturally unrelated to database write-privilege reduction.

Security and governance

Centriu Vértice's direct database write surface for unauthenticated and ordinary-authenticated credentials was reduced from 827 objects to 2 confirmed-legitimate exceptions, following a measurement combining a policy-reachability audit, a whole-module code inventory, and a mandatory live adversarial test phase that caught and discarded false positives before publication. Any personal data referenced in member records 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 on a single plan. Values and terms come from the official pricing table at /precos (Centriu's central source — never restated here).

Frequently asked questions

Why not just close all 827 objects immediately, without measuring first?

Closing all 827 identically would have reached the same final database state, but without measuring which findings were real, it also risked publishing a false claim — a status-reinstatement path a static reading suggested was open, that a mandatory live test found was already blocked by an existing database trigger.

How did 827 objects become just 7 real exposures?

414 had row-level security with zero policies (dead on arrival), 208 had read-only policies (also dead on arrival) — 622 already inert. Of the remaining 203, 137 require a role ordinary members don't hold. The last 66 collapse into 11 policy patterns, and a live adversarial test against a real database confirmed exactly 7 of those represented genuine, reproducible exposures.

What is the "mandatory phase 0" test, and why does it matter?

It's a required step attempting each specific write directly against a real, live-configured database BEFORE any finding is written down as confirmed — specifically to catch cases where a static reading of access rules suggests a write is possible, but a separate mechanism (here, a database trigger) already blocks it in practice.

Why did the fix need a lock-wait limit?

Revoking a privilege requires an exclusive lock on each affected object, and this fix touches roughly 878 objects in one transaction — all locks held until commit. Without an explicit wait limit, one unrelated long-held lock anywhere in that set could queue the entire site's traffic behind the migration. The limit makes the migration fail fast and visibly instead.

Does this affect what a legitimate Vértice member can actually do?

No — the 2 write paths this investigation confirmed as genuine member self-service actions are explicitly preserved, and the migration includes a built-in check confirming they still work before considering itself successful.

What does Centriu Vértice cost?

It is sold by subscription with a published starting price — exact current values are on the central pricing page.

See how Centriu Vértice measures database access before closing it

Reach our commercial team directly, or leave your details below — we'll follow up with guidance for your case.

Sources

  1. Centriu Vértice — public product page — Centriu, 2026-07-20 · link(primária)
  2. Centriu Vértice — public factsheet (API, JSON) — Centriu, 2026-07-21 · link
  3. Law No. 13,709/2018 — Brazil’s General Data Protection Law (LGPD) — Presidência da República (Brazil), 2018-08-14 · link

Last material update on .

By · AI-assisted production, with human review