How card-data entitlements actually work - an Atlas teardown. A teardown by Kaushal Khodifad, founder of CLOZOM, published 12 Sep 2026. Row-level entitlements, column masking and audit written into Postgres instead of application code, and the four ways the pattern breaks after it ships. Every factual claim in the piece is cited to a source listed at the foot of the page.

19 min read

How card-data entitlements actually work - an Atlas teardown

An entitlement that lives in application code is a claim about every code path that will ever exist. An entitlement that lives in the database is an artifact somebody else can read.

Payments dataRow-level securityPostgresAudit evidenceGovernance

Updated

Every analytics platform built over card transactions eventually runs into the same question, and it is almost never an engineer who asks it. Someone from risk, or a partner's counsel, or an internal auditor asks who is allowed to see this row. Then comes the hard half: show me why it could not have been seen by somebody else.

There are two places to answer that. In the application, where a request carries an identity, a service resolves it to a set of permissions, and a query builder appends a where clause. Or in the database, where the row simply does not come back. Both filter correctly on the happy path. Only one of them is evidence.

An entitlement in application code is a claim about every code path. An entitlement in the database is an artifact somebody else can read.

What follows is how the database version actually works: the policy algebra that trips up most first implementations, the thing that carries identity into a policy, the function attribute that silently switches enforcement off, why column masking is not a policy at all, and the four ways this pattern breaks after it ships.

The gap that survives code review

Application-layer filtering is not wrong. It is unprovable, which is a different and costlier problem.

The OWASP API Security Top 10 puts Broken Object Level Authorization at number one, and its prevention guidance is worth reading as a specification rather than as advice. It tells you to use the authorization mechanism to check whether the logged-in user may perform the requested action on the record, and then adds the three words that decide the architecture: "in every function" that takes client input and uses it to reach a record.1

Check authorization is tractable. Check it in every function is a universal claim over a codebase that grows every sprint, and nobody closes a universal claim by inspection. The set of functions that read the transactions table is never the set you reviewed. It is that set plus the CSV export somebody added for a partner, the nightly job that refreshes a materialized view, the notebook on the read replica the data team got in Q3, and whatever an engineer wired to the warehouse last month so a model could answer questions about spend.

The audit consequence is why this matters commercially. An auditor does not ask whether you filter. Everybody filters. They ask you to demonstrate the filter could not have been skipped, and a code review cannot demonstrate anything about code that does not exist yet. A policy attached to the table can, because the next code path inherits it without knowing it is there.

The BI layer enforces for exactly one consumption path

The plane many organisations actually rely on is the semantic layer in a BI tool, and its limits are documented by the vendors themselves rather than by critics. Microsoft's documentation for row-level security in Power BI states four things plainly. RLS restricts data access for users with Viewer permissions and does not apply to the workspace Admin, Member, or Contributor roles. Service principals cannot be added to an RLS role, so RLS is not applied for apps using a service principal as the final effective identity. Asked whether RLS can limit the columns or measures a user reaches, the FAQ answers no: access to a row means access to every column of that row. And when data is imported rather than queried through DirectQuery, the security roles defined in the data source are not used.2

Every one of those is a defensible decision. A Contributor can edit the model, so filtering their view would be theatre. A service principal is an application identity, not a person. Column-level control is a different mechanism with a different name. Import mode is a copy, and a copy cannot consult the original's roles. Read together, though, they describe a boundary: the semantic model enforces for people consuming through the semantic model, as viewers. It was never built to enforce for the export, the replica, the notebook or the service account.

Warehouses make a different choice. Snowflake evaluates a row access policy at query runtime, but it evaluates the expression using the role of the policy owner rather than the role of the operator who ran the query.3 That is deliberate and useful: it lets a policy consult a mapping table the querying role may not read. It also means whose privileges evaluate this policy is a decision you make on purpose, in every engine, before you can state what your model guarantees.

So the question to ask of any enforcement plane is not whether it works. It is which consumption paths it covers, and what happens on the ones it does not.

Where the entitlement goes instead

Permissive policies OR together, which is the opposite of the goal

The instinct is one policy per rule: partner scope, purpose, region, and the table ends up with five. That instinct produces the exact opposite of the intended behaviour.

When multiple policies apply to a query, Postgres combines them with OR for permissive policies and AND for restrictive ones, and permissive is the default.4 The CREATE POLICY page is explicit about direction: permissive policies add to the set of records that can be accessed, restrictive policies reduce it, and every applicable restrictive policy must pass for each record.5 Five rules written as five default policies do not narrow anything. Each is another way in.

The inverse bites too. There must be at least one permissive policy granting access before restrictive policies can usefully reduce it, and if only restrictive policies exist then no records are accessible.5 That failure presents as a table returning zero rows to everybody while each policy looks correct on its own.

The shape that works is one permissive base plus N restrictive subtractors. It looks wrong the first time you write it, because the base policy grants everything:

sql

-- baseline visibility the restrictive policies then subtract from
create policy txn_base on atlas.synthetic_transactions
  for select to anon, authenticated using (true);

-- a partner analyst only ever sees that partner's rows
create policy txn_partner_scope on atlas.synthetic_transactions
  as restrictive for select to anon, authenticated
  using (
    case current_setting('app.role', true)
      when 'partner_analyst_nova' then partner_scope = 'nova'
      else true
    end
  );

-- confirmed-fraud rows require BOTH a fraud purpose and a fraud-capable role
create policy txn_fraud_purpose on atlas.synthetic_transactions
  as restrictive for select to anon, authenticated
  using (
    is_fraud = false
    or (
      current_setting('app.purpose', true) = 'fraud_prevention'
      and current_setting('app.role', true)
          in ('fraud_analyst','data_scientist','auditor','admin')
    )
  );
The base policy is deliberately using (true). It exists so the restrictive policies below it have something to subtract from.

Note what the second restrictive policy does, because it reads as a product decision rather than a security control. Under any purpose but fraud prevention, confirmed-fraud rows are not hidden, redacted or greyed out. They are not in the result set, so a count(*) returns a number that does not include them. Purpose limitation, which in GDPR terms means data collected for specified purposes and not further processed in a way incompatible with those purposes,11 turns out to be expressible as a boolean in a predicate.

enable is a switch, force is the line that matters

Superusers and roles carrying the BYPASSRLS attribute always bypass row security. Table owners normally bypass it as well, unless the owner opts in with ALTER TABLE ... FORCE ROW LEVEL SECURITY.4

Most tutorials show the first line and not the second. The result is a system where RLS demonstrably works through the application, which connects as a low-privilege role, and quietly does not exist for the migration user, the analyst at a psql prompt, or the ETL job. Those accounts touch the most data. Both lines, on every protected table:

sql

alter table atlas.synthetic_transactions enable row level security;
alter table atlas.synthetic_transactions force  row level security;

The policy subject is a transaction-local setting, not a login

Most RLS examples write policies against the authentication system's session identity. That works, and it welds your entitlement model to one authentication scheme. The general form is to have the policy read a run-time configuration parameter and have the read path set it.

Two details in the Postgres admin functions make that safe. set_config(name, value, is_local) with is_local true applies the new value only for the current transaction, and current_setting(name, missing_ok) returns NULL instead of raising when the setting was never set.7 So the context is established and discarded inside the same transaction as the read:

sql

perform set_config('app.role',    coalesce(p_role, ''),    true);
perform set_config('app.purpose', coalesce(p_purpose, ''), true);
The third argument is the whole design. true means transaction-local, which is what keeps one request's context out of the next one.

One consequence is pleasant: a platform can enforce real entitlements for an identity that has no database login, because identity arrives as context rather than as a connection. The other is a constraint. Whoever calls the function chooses the context, which is acceptable only if the function is the sole read path and the caller cannot name its own role. In production that value comes from a verified server-side session, never from a request parameter.

SECURITY INVOKER, SECURITY DEFINER, and the bypass nobody asked for

SECURITY INVOKER runs a function with the privileges of the user that calls it, and it is the default. SECURITY DEFINER runs it with the privileges of the user that owns it.6 Separately, policy expressions run as part of the query with the privileges of the user running the query, though security-definer functions can be used to reach data the calling user cannot.4

Put those together and DEFINER stops being a calling convention and becomes a privilege boundary. A DEFINER function owned by the table owner skips RLS entirely unless FORCE is set, and even with FORCE set, the policies that apply are the ones attached to the owner's role rather than the caller's. A common way to lose row-level security you configured correctly is for somebody to wrap a query in a helper and mark it DEFINER to clear a permissions error in staging.

The discipline is to answer the question separately for every function. Three in my system matter, and each answers it differently:

  • The read functions, query_dataset and run_select, are SECURITY INVOKER. They execute as the caller, so every read is scoped by the same policies as a raw query.
  • The audit writer, log_access, is SECURITY DEFINER for exactly one reason: the calling role is deliberately granted no INSERT on the audit table. DEFINER here grants one narrow capability upward. It is not used to get around a filter.
  • The dashboard aggregate, dashboard_stats, is SECURITY DEFINER and therefore bypasses RLS on purpose, acceptable only because it returns counts, rates and sums and never a row or a PII field. That reasoning sits in the migration next to the function, because a bypass you cannot explain in a comment is one you should not have.

Every DEFINER function here pins its search_path to the schemas it needs. The documentation gives both the reason and the stricter form: the path should exclude any schema untrusted users can write to, and the reliable arrangement is to force the temporary schema to be searched last by writing pg_temp as the final entry, so a temporary table cannot shadow the object the function meant to use.6

Column masking is a projection, not a policy

RLS filters rows. It does not restrict columns, and the same limit shows up on the BI side, where access to a row means access to every column of it.2 So masking cannot be a policy. It lives in the select list of whatever returns the data:

sql

case when v_can_unmask then email else atlas.mask_email(email) end as email,
case when v_can_unmask then phone
     else '***-***-' || right(phone, 4) end as phone

The distinction most demos get wrong is not how to mask. It is what an entitlement may unlock versus what nothing unlocks. Here the acting role changes what happens to account tokens and contact PII. It never changes the card number: that column is stored masked and returned masked to every role including the administrator, because no business purpose in the platform requires the clear value.

The PCI Security Standards Council's FAQ on truncation is why you should be strict about that. It sets a maximum of the first six and last four digits as the baseline an entity may retain, and warns that access to different truncation formats of the same number greatly increases the ability to reconstruct it.10 The second half is the part people miss: masking is a property of the system, not of a view, and a second view that truncates differently undoes the first.


Four ways this breaks after it ships

1. The connection pooler

This is the one that catches teams who did everything else right, and it follows directly from putting identity in a session variable. PgBouncer's transaction pooling mode shares one physical backend across many clients, and its SQL feature map lists SET and RESET as never available in that mode. The documentation is blunt: the mode breaks session-based features of Postgres and works only when the application cooperates by not using them.8

Set the entitlement context session-wide and you have built a cross-tenant leak with a clean audit log. The value outlives the request that set it, the backend returns to the pool, and the next tenant's query runs under whatever identity the previous one left behind. The context has to be transaction-local and set inside the same transaction as the read, which is the structural reason the set_config calls and the select live in one function body rather than in two round trips from the application.

2. The direction a policy fails in, which NULL chooses for you

Look again at the partner scope policy above and follow the NULL. current_setting('app.role', true) returns NULL when the setting was never established.7 A case on NULL matches no when branch, so it falls to else, and else is true.

That policy therefore fails open: an unset context removes the partner restriction entirely. Its neighbour on the same table fails the other way. With app.purpose unset the purpose comparison is NULL, so for a confirmed-fraud row the predicate evaluates to NULL rather than true and the row drops out. Two restrictive policies, one table, opposite defaults, and nothing in either expression announces which. In my system the open one is defensible, and only just: there is one read path, it always sets the context, and the data is synthetic. In a real issuer it would be indefensible, and the predicate would invert, so an absent or unrecognised context returns zero rows and somebody gets paged.

3. The predicate runs per row, before your query does

A row-security expression is evaluated for each row prior to any conditions or functions coming from the user's query.4 That one sentence explains most complaints that RLS is slow. The policy predicate is not an afterthought applied to a small result set. It is evaluated as rows are scanned, so an unindexed column that a policy tests is paid for on every query that touches the table.

Supabase's troubleshooting guidance is the most concrete public writeup of the fix, and the numbers are theirs: index the columns your policies test, where they report improvements of over 100x on large tables, and wrap a function call in a subselect so the optimizer evaluates it once as an initPlan rather than once per row, a change they benchmark from roughly 11,000ms to roughly 7ms. The same page recommends naming the approved roles in the policy's TO clause, so unqualified callers are eliminated before any policy logic runs.9 The indexes worth having are not the ones an ORM would generate. They are the columns the restrictive policies test.

4. RLS narrows the result set; it does not make the database silent

Two side channels are worth knowing about, because neither is a bug and neither goes away. Referential integrity checks, including unique and primary key constraints and foreign key references, always bypass row security so data integrity is maintained, and the documentation warns about designing schemas and policies to avoid a covert channel here.4 A unique-violation error can confirm a row exists that the caller may not see. Separately, the optimizer may apply leakproof functions ahead of the row-security check,4 so a chosen expression plus a verbose error message forms a second channel.

Neither undermines the case for entitlements in the data plane. Both undermine the idea that turning on RLS finishes the job.


The audit row belongs inside the read

Most platforms log data access next to the read: the service fetches rows, then emits an event to a logging pipeline. Two systems that can diverge, and the component writing the record is the component being audited. You find out they disagreed during the investigation. The alternative costs one line. The function that returns the rows writes the audit record before it returns, in the same transaction:

sql

perform atlas.log_access(p_role, p_purpose, p_dataset, v_count, not v_can_unmask);
It sits inside query_dataset, after the count and before the return. The calling role holds SELECT on the audit table and no INSERT, so it cannot write or erase what it can read.

What that buys is a state the system cannot reach. Rows returned with no audit row is not a failure mode, because the transaction that produced one produced the other. Neither is a forged or deleted entry, because the grant does not permit either.

This is where the regulation lands. GDPR Article 5(2) requires the controller to be responsible for the principles in 5(1) and to be able to demonstrate compliance with them,11 and those principles are the ones this design implements directly: purpose limitation in 5(1)(b), minimisation in 5(1)(c), integrity and confidentiality in 5(1)(f). Able to demonstrate is a separate obligation from having done the right thing. A log the application writes records what the application believes happened. A row written by the transaction that returned the data records what the database did.

2026 turned this from a governance topic into a category

For most of the past decade, who can see which rows was a governance conversation on a quarterly cadence. In a single quarter of 2026 the access-control market repositioned around identities that have no user interface.

  • On 24 March 2026, Immuta announced a data provisioning platform for managing agentic data access, built on zero standing privileges, provisioning temporary access directly in the underlying data platform and removing it when the task completes, treating the agent as an identity distinct from the user it acts for.23
  • On 5 March 2026, Delinea completed its acquisition of StrongDM, on the stated rationale that privileged access is increasingly required by non-human identities operating autonomously, and that pairing privileged access management with authorization at the moment of action is what makes zero standing privilege practical.24
  • On 19 March 2026, Oasis Security announced a $120 million Series B led by Craft Ventures, with Cyberstarts, Sequoia and Accel participating, for governing machine identities across cloud and AI environments.25

I am not evaluating any of the three, and none competes with a Postgres policy. The signal is the agreement: three independent commercial bets in three weeks on the proposition that the actor requesting data increasingly has no session, no viewer role and no workspace membership. An agent generating SQL against your warehouse is the purest case of the code path nobody reviewed. It has no UI, so a UI-layer entitlement does not exist for it, and it writes queries you did not, so a query-builder entitlement does not constrain it.

The corollary is the payoff, and it is why the natural-language query console sits on the same plane as everything else. The function that executes model-generated SQL is SECURITY INVOKER, so a generated query meets exactly the same policies as a hand-written one, with no separate code path and no second policy engine to keep in sync. There are string guards on top, because defence in depth is cheap: SELECT and WITH only, single statement, keyword and cross-schema denylists, a four-second timeout, a hard limit wrapper. None of those is the control. The control is that the executing role holds SELECT and nothing else. Ask that engine for a count of confirmed-fraud rows under a marketing purpose and it returns zero, not because a filter was applied to the answer but because those rows were not in the table it read.

What the supervisor actually asks for

The Basel Committee published BCBS 239, the Principles for effective risk data aggregation and risk reporting, on 9 January 2013.12 Its 2023 progress report assessed 31 global systemically important banks and found that, nearly ten years after publication and seven years after the expected date of compliance, banks are at different stages in terms of alignment.13

The committee's newsletter of 6 January 2026 is the fresher and more useful read, because it names the thing that is still hard. Data lineage, which it defines as the traceability of data from its origin to its final use, is important for confirming data quality, and legacy systems together with distributed data estates complicate banks' efforts to confirm end-to-end traceability. The same note observes that because the quality of AI-driven outputs depends on high-quality data, robust data management becomes more important.14

Traceability is the word to sit with. The supervisory question is not was access controlled. It is can you trace it, a question about artifacts rather than intentions, and it is the auditor's question from the top of this piece in different clothes.

Supervisors price the answer. On 10 July 2024 the Federal Reserve announced a $60.6 million penalty against Citigroup, stating that the firm had made insufficient progress remediating its problems with data quality management and had failed to implement compensating controls to manage its ongoing risk; combined Federal Reserve and OCC penalties totalled approximately $135.6 million.15 The OCC's $75 million civil money penalty was assessed on the bank's violations of a 2020 order and a lack of processes to monitor the impact of data quality concerns on regulatory reporting.16

And the set of parties reading your tables keeps growing. The CFPB issued its Required Rulemaking on Personal Financial Data Rights on 22 October 2024, published in the Federal Register on 18 November 2024, requiring providers to make consumer data available to consumers and authorised third parties.17 Its status is genuinely unsettled: the Bureau issued an advance notice of proposed rulemaking on 22 August 2025 under docket CFPB-2025-0037, reconsidering who qualifies as a representative, how fees should be assessed, and the security and privacy questions,18 and on 29 October 2025 Judge Danny Reeves of the Eastern District of Kentucky granted a preliminary injunction in Forcht Bank, N.A. v. CFPB, No. 5:24-cv-00304-DCR, enjoining the Bureau from enforcing the current final rule until it has completed its reconsideration.2122 The rewrite has since moved further along: the Bureau's own Unified Agenda entry carries Personal Financial Data Rights Reconsideration at the proposed rule stage,19 and in August 2026 it sent that proposal to the Office of Information and Regulatory Affairs for review, which is generally one of the last steps before a proposal is published in the Federal Register for comment.20 Its substance is not yet public.

For a platform team the rule's final text matters less than what the fight is about. An authorised third party holding a consumer's permission is another consumption path over the same tables, arriving with its own identity, its own purpose and no user interface. That is the agent's question from a different direction, with a regulator attached.

Ten seconds of proof

All of it is checkable in a browser, which is why I can be this specific. Atlas is a card-data analytics prototype I built on synthetic data, generated in-database with a fixed seed so it reproduces, with no real or clear card number in it at any point. Change the acting role from the administrator to a partner analyst and the row count drops to that partner's slice, the tokens mask, and a new audit row appears, because a restrictive policy tested a transaction-local setting on a low-privilege Postgres role. Change the purpose away from fraud prevention and the confirmed-fraud rows stop existing for that query. No application code made either decision, and the six SQL files that did are in the repository.

One detail I would want in somebody else's version of this. A second, independent TypeScript implementation of the same policies and the same masking projection lives in the repository, and the live page runs every result set Postgres returns through it. If the deployed database drifted from the committed SQL, the page would flag the violating rows rather than quietly render the wrong data. Two implementations agreeing is evidence. Disagreement is a visible failure, which is the only kind worth having.

Sources

Every claim above, traceable.

Primary sources where one exists. The access date is the day the page was read, because pages change.

  1. 1.
    API1:2023 Broken Object Level Authorization

    OWASP API Security Top 10 (2023 edition) · api-security.owasp.org · read 2026-09-12

    Prevention guidance requiring the authorization check in every function that uses client input to reach a record.

    Back to the first citation of back to text
  2. 2.
    Row-level security (RLS) with Power BI

    Microsoft Learn · learn.microsoft.com · read 2026-09-12

    Viewer-only scope, service principals excluded, no column restriction, and import mode ignoring data source roles.

    Back to the first citation of back to text
  3. 3.
    Understanding row access policies

    Snowflake Documentation · docs.snowflake.com · read 2026-09-12

    Policies are evaluated at query runtime using the role of the policy owner, not the operator who ran the query.

    Back to the first citation of back to text
  4. 4.
    Row Security Policies

    PostgreSQL 17 Documentation · postgresql.org · read 2026-09-12

    Policy combination, BYPASSRLS and owner bypass, FORCE ROW LEVEL SECURITY, per-row evaluation order, referential integrity bypass.

    Back to the first citation of back to text
  5. 5.
    CREATE POLICY

    PostgreSQL 17 Documentation · postgresql.org · read 2026-09-12

    Permissive policies add access and combine with OR; restrictive policies reduce it and combine with AND; restrictive-only means nothing is accessible.

    Back to the first citation of back to text
  6. 6.
    CREATE FUNCTION

    PostgreSQL 17 Documentation · postgresql.org · read 2026-09-12

    SECURITY INVOKER as the default, SECURITY DEFINER semantics, and the search_path guidance including pg_temp last.

    Back to the first citation of back to text
  7. 7.
    System Administration Functions

    PostgreSQL 17 Documentation · postgresql.org · read 2026-09-12

    set_config with is_local true applies only for the current transaction; current_setting with missing_ok returns NULL.

    Back to the first citation of back to text
  8. 8.
    PgBouncer features and SQL feature map for pooling modes

    PgBouncer · pgbouncer.org · read 2026-09-12

    SET and RESET are listed as never available in transaction pooling mode.

    Back to the first citation of back to text
  9. 9.
    RLS Performance and Best Practices

    Supabase Docs · supabase.com · read 2026-09-12

    Indexing policy columns, wrapping function calls so the optimizer runs an initPlan, naming roles in the TO clause, and adding a query filter in addition to RLS rather than relying on RLS to filter.

    Back to the first citation of back to text
  10. 10.
    What are acceptable formats for truncation of primary account numbers?

    PCI Security Standards Council · pcisecuritystandards.org · read 2026-09-12

    First six and last four as the retention baseline, and the reconstruction risk from multiple truncation formats of the same number.

    Back to the first citation of back to text
  11. 11.
    Art. 5 GDPR: Principles relating to processing of personal data

    Regulation (EU) 2016/679 · gdpr-info.eu · read 2026-09-12

    Purpose limitation, minimisation, integrity and confidentiality, and the accountability obligation to be able to demonstrate compliance.

    Back to the first citation of back to text
  12. 12.
    Principles for effective risk data aggregation and risk reporting

    Basel Committee on Banking Supervision, BIS · bis.org · read 2026-09-12

    Published 9 January 2013.

    Back to the first citation of back to text
  13. 13.
    Progress in adopting the Principles for effective risk data aggregation and risk reporting

    Basel Committee on Banking Supervision, BIS · bis.org · read 2026-09-12

    28 November 2023; 31 G-SIBs assessed; banks at different stages of alignment.

    Back to the first citation of back to text
  14. 14.
    Newsletter on the implementation of the Principles for effective risk data aggregation and risk reporting

    Basel Committee on Banking Supervision, BIS · bis.org · read 2026-09-12

    6 January 2026, on lineage, end-to-end traceability and the dependence of AI output quality on data quality.

    Back to the first citation of back to text
  15. 15.
    Federal Reserve Board fines Citigroup $60.6 million

    Board of Governors of the Federal Reserve System · federalreserve.gov · read 2026-09-12

    10 July 2024; insufficient progress on data quality management; approximately $135.6 million combined with the OCC.

    Back to the first citation of back to text
  16. 16.
    OCC assesses civil money penalty against Citibank

    Office of the Comptroller of the Currency · occ.gov · read 2026-09-12

    $75 million, based on violations of the 2020 order and a lack of processes to monitor data quality impacts on regulatory reporting.

    Back to the first citation of back to text
  17. 17.
    Required Rulemaking on Personal Financial Data Rights

    Consumer Financial Protection Bureau · consumerfinance.gov · read 2026-09-12

    Final rule issued 22 October 2024, published in the Federal Register 18 November 2024.

    Back to the first citation of back to text
  18. 18.
    Personal Financial Data Rights Reconsideration

    Consumer Financial Protection Bureau · consumerfinance.gov · read 2026-09-12

    Advance notice of proposed rulemaking issued 22 August 2025, docket CFPB-2025-0037.

    Back to the first citation of back to text
  19. 19.
    Unified Agenda entry for RIN 3170-AB39, Personal Financial Data Rights Reconsideration

    Office of Information and Regulatory Affairs, reginfo.gov · reginfo.gov · read 2026-09-13

    The government's own record of the rewrite: Proposed Rule Stage, ANPRM of 22 August 2025 at 90 FR 40986, NPRM projected for July 2026. No proposal text is published, so the substance is not yet public.

    Back to the first citation of back to text
  20. 20.
    CFPB sends new Section 1033 open banking proposal to OIRA for review

    Consumer Finance Monitor, Ballard Spahr · consumerfinancemonitor.com · read 2026-09-12

    6 August 2026. The only source I can find for the date the proposal reached OIRA for Executive Order 12866 review; reginfo.gov publishes the agenda entry but not the review submission.

    Back to the first citation of back to text
  21. 21.
    Memorandum Opinion and Order granting a preliminary injunction, Forcht Bank, N.A. v. Consumer Financial Protection Bureau, No. 5:24-cv-00304-DCR (E.D. Ky.), Doc. 90, filed 29 October 2025

    United States District Court for the Eastern District of Kentucky, stamped copy hosted by Reuters · fingfx.thomsonreuters.com · read 2026-09-13

    The order itself, signed by Judge Danny C. Reeves: "The Consumer Financial Protection Bureau is ENJOINED from enforcing the Personal Financial Data Rights Rule until it has completed its reconsideration of the Rule."

    Back to the first citation of back to text
  22. 22.
    Kentucky federal court enjoins CFPB from enforcing current 1033 final rule

    ABA Banking Journal · bankingjournal.aba.com · read 2026-09-12

    Coverage of the same order, for context on what the injunction means for the June 2026 compliance deadline.

    Back to the first citation of back to text
  23. 23.
    Immuta Introduces the First Data Provisioning Platform for Managing Agentic Data Access

    Immuta, via PR Newswire · prnewswire.com · read 2026-09-12

    24 March 2026. Zero standing privileges, temporary access provisioned in the underlying data platform and removed on completion.

    Back to the first citation of back to text
  24. 24.
    Delinea Completes StrongDM Acquisition to Secure AI Agents with Continuous Identity Authorization

    Delinea, via GlobeNewswire · globenewswire.com · read 2026-09-12

    5 March 2026. Non-human identities operating autonomously, least privilege at the moment of action, zero standing privilege.

    Back to the first citation of back to text
  25. 25.
    Oasis Security Raises $120M Series B to Secure the Rise of Enterprise AI Agents

    Oasis Security, via ACCESS Newswire · accessnewswire.com · read 2026-09-13

    The company's own release, 19 March 2026. Series B led by Craft Ventures with Cyberstarts, Sequoia and Accel participating.

    Back to the first citation of back to text