Ledger Append-Only Enforcement Automation: Membership Answered a Question It Was Never Asked

Belonging to an organization and being allowed to make a specific kind of change are two different questions
Row-level security scoped to organization membership answers a genuinely important question — whose data is this — and for the great majority of a product's own tables, that answer is also the complete answer to who may write to them: any member of an organization can reasonably read and write their own organization's ordinary operational records. A financial ledger is a specific, narrower case: its entire value as a ledger comes from being a trustworthy, permanent history of what happened, which means the real question for an UPDATE or DELETE on one of its rows is never really "does this caller belong here" — it is "should this kind of change be possible at all, by anyone, outside the one function built to apply it correctly." A security model that only ever answers the first question has, by construction, no way to also answer the second.
How the underlying problem shows up before you fix it
A financial or historical record's own row-level security is scoped entirely to organization or tenant membership, with the identical read-and-write permission granted uniformly to every member regardless of what kind of change is being attempted.
A table's own default database privileges (granted automatically to every new table by the platform) include UPDATE and DELETE for roles that have no legitimate reason to ever issue either operation directly against that specific table — including, in the most severe version of this gap, the application's own backend connection itself.
A dedicated function exists specifically to apply changes to a record correctly (here, recording a ledger movement and updating a running balance in the same transaction) — but nothing stops the identical underlying table from also being reachable by a direct write that completely bypasses that function, and everything it enforces along the way.
A record whose entire purpose is serving as a permanent, trustworthy account of what happened (a ledger, an audit trail) has no database-level protection against being altered or deleted after the fact, relying only on the absence of a client-side button rather than an actual data-layer guarantee.
Measuring this class of gap correctly requires a genuine, ordinary member's own identity in the test — a test accidentally run as a superuser or other privileged role will report the write as blocked even where, for an ordinary member, it is not, producing a false sense of security.
Why tenant-scoped access feels complete until a write needs its own, separate rule
Granting any organization member equal read-and-write access to their own organization's tables is the natural default, and for the overwhelming majority of a product's tables, it is also the entirely correct one — most operational data genuinely is meant to be editable by any legitimate member. The gap opens specifically for the narrower class of record where the real rule is not about WHO but about WHAT KIND of change: a ledger, by definition, is supposed to only ever grow, never be edited or shrunk after the fact, and that property has to be enforced as its own explicit, separate rule — it is not something ordinary tenant-scoped access control was ever built to express on its own, and a table's default database privileges, granted automatically on creation, will not narrow themselves down to match that stricter rule without someone deliberately doing so.
How Centriu Loop made its ledger genuinely append-only
Centriu Loop's own cashback ledger previously enforced only organization-scoped row-level security — any authenticated member of the organization a row belonged to could read it, and, because the table's own default database privileges had never been narrowed, could also directly UPDATE or DELETE it, entirely outside the dedicated function meant to apply and record every legitimate movement correctly.
The fix closes the gap with three independent, deliberately overlapping layers, because the migration's own reasoning is explicit that no single one is sufficient alone. First, a database trigger fires before any update or delete on the ledger table and unconditionally raises an explicit error — and this layer is enforced even for the platform's OWN privileged backend connection, which normally bypasses row-level security by design as the trusted path the application itself uses. That is a deliberate, stricter choice than exempting a trusted backend identity: correcting a mistaken ledger entry, even from the application's own official code path, must always mean recording a new, separate, opposite entry — never editing or deleting the original. Second, the permissive update policy that had allowed the write is removed outright. Third, the underlying UPDATE, DELETE, and TRUNCATE privileges themselves are revoked from every role the table had ever granted them to — closing the gap not just for the row-level security layer, but for the privilege layer underneath it as well.
The fix was measured directly against a real PostgreSQL 16 database, before and after, using the schema state that matched what production's own catalog showed at the time. The first attempt at that measurement produced a false result: a `set local` statement used to simulate an ordinary member's identity, issued outside an explicit transaction block, silently has no effect in PostgreSQL — the session quietly continued running as the database superuser, which bypasses row-level security entirely by design. What caught the error was a POSITIVE CONTROL built into the same test: a cross-tenant write, from a different organization entirely, that should always fail regardless of anything else being tested. When that control unexpectedly "succeeded," it proved the instrument itself was not measuring what it claimed to measure — a superuser can write anywhere, tenant or no tenant. The test was corrected to genuinely assume an ordinary member's identity inside its own transaction, and re-run: the same-org member's UPDATE returned exactly one affected row before the fix and zero — a genuine permission denial — after it; DELETE showed the identical pattern; the cross-tenant control correctly failed in both runs; and an ordinary, legitimate read of the same row was completely unaffected, returning the identical single row before and after.
What is actually built today
Centriu Loop's ledger table rejects any UPDATE or DELETE with an explicit database error, enforced even for the platform's own privileged backend connection — correcting a mistake always means recording a new entry, never editing the old one.
The permissive row-level security policy that had allowed a same-organization member to update the ledger directly has been removed.
The underlying UPDATE, DELETE, and TRUNCATE database privileges on the ledger table have been revoked from every role, closing the gap at the privilege layer as well as the policy layer.
An ordinary, legitimate read of a ledger row is completely unaffected by any of these changes — the guarantee applies specifically to write operations that would alter or remove an existing, already-recorded entry.
The fix was measured directly against the live production database's own permission catalog, before and after, including a same-organization member, a cross-tenant control, and a legitimate read — not inferred from the migration's source code alone.
A history book anyone in the office could quietly rewrite (illustrative framing of the actual measured finding)
Before the fix, an ordinary member of their own organization could issue a direct UPDATE against a real ledger row and have it succeed — altering a permanent financial record with the same ease as editing an ordinary settings field, entirely outside the function meant to apply and validate a legitimate change. After the fix, the identical UPDATE, issued by the identical member against the identical row, is refused outright by the database itself — measured directly, not merely reasoned about, against Loop's own live production catalog.
What changes operationally
Centriu Loop's cashback ledger now rejects any direct update or delete at the database level itself — through a trigger, a removed policy, and a revoked privilege, together — closing a gap where any authenticated member of their own organization could alter or delete a permanent financial record directly, bypassing the function meant to apply and validate every legitimate movement.
When this is not the right fit
This automation covers specifically the write-protection of Centriu Loop's own cashback ledger table. It is a distinct mechanism from this pillar's separate pages on Loop's expiration and reconciliation model, and on how a wrongful credit is now corrected as a distinct chargeback entry — both build on top of this same append-only foundation but address different, separately-covered questions.
Tenant-scoped write access vs. an explicit, layered append-only guarantee
Granting any organization member equal read-and-write access to their own organization's records is simpler to build and correct for the great majority of a product's own tables. A ledger is a deliberate exception: its value depends entirely on being unable to be rewritten after the fact, a property tenant-scoped access alone was never built to express. Enforcing that property at three independent layers — a trigger, a policy, and the underlying privilege grant — rather than any single one alone, is the only version of the two that survives a gap being found in any one specific layer, which is exactly the reasoning the fix's own migration states explicitly.
Related systems
Main system: Centriu Loop.
What it does NOT do
- Does not prevent a genuine correction to a mistaken ledger entry — it requires that correction to be recorded as a NEW, separate, opposite entry, never as an edit or deletion of the original record.
- Does not exempt the application's own backend connection from the append-only guarantee — a deliberate, stricter choice than a typical privileged-role exemption, closing the gap even for the platform's own trusted server-side path.
- Does not affect ordinary, legitimate reads of ledger data — measured directly to confirm a read returns the identical result before and after the fix.
- Does not overlap with this pillar's separate pages on Loop's expiration/reconciliation model or its chargeback-vs-adjustment distinction — both build on this same append-only foundation but cover genuinely different, separately-documented mechanisms.
- Does not extend this same three-layer append-only pattern to any other table in Centriu's other systems — this fix is specific to Loop's own ledger table, confirmed to have carried this exact gap.
Security and governance
Centriu Loop's cashback ledger now rejects any direct update or delete at the database level — through a trigger enforced even for the platform's own backend connection, a removed policy, and a revoked privilege — closing a gap where an authenticated member of their own organization could alter or delete a permanent financial record directly. Any personal or financial data referenced in ledger 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 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
Could someone outside my organization have reached my ledger through this gap?
No — row-level security correctly continued to block any cross-tenant attempt throughout, measured explicitly as part of the same before-and-after test. The gap was specific to what a genuine member of the SAME organization could do, not to cross-organization access.
How does a genuine mistake in the ledger get corrected now?
By recording a new, separate, opposite entry through the ledger's own dedicated function — never by editing or deleting the original record. The historical record of what actually happened, including the original mistake, is preserved completely.
Why does the fix block even the application's own backend from updating or deleting a ledger row?
Because the whole value of an append-only ledger depends on nothing, including the platform's own trusted code, ever rewriting history — even a legitimate correction has to take the form of a new entry, which is what the ledger's own dedicated function already does.
How was this actually confirmed fixed, rather than just written into a migration file?
By running a direct, measured before-and-after test against the live production database's own catalog — an ordinary member's UPDATE and DELETE attempts, a cross-tenant control, and a legitimate read — rather than relying on the migration's source code alone.
What went wrong the first time this was measured, and how was it caught?
The first attempt accidentally ran as the database superuser instead of an ordinary member, because a role-switching statement issued outside a transaction silently had no effect. A positive control in the same test — a cross-tenant write that should always fail — unexpectedly succeeded, which is only possible for a superuser, revealing the mistake before a false result could be reported.
What does Centriu Loop cost?
It is sold by subscription with a published starting price — exact current values are on the central pricing page.
See how Centriu Loop keeps its own ledger append-only
Reach our commercial team directly, or leave your details below — we'll follow up with guidance for your case.
