Power Pages Data Leaks: Getting Table Permissions and Web Roles Right
A troubleshooting reference for the team whose portal users can see other customers' records: contain it, establish what the logs can prove, rebuild the permission model and test it as real users.
If a signed-in Power Pages user can see other customers' records, contain it first: switch off the list, form or page showing the data, remove or narrow the table permission granting it, and disable the Web API site setting for that table. Next, establish exposure from sign-in logs and any Application Insights or diagnostic logging you had enabled, remembering that Dataverse auditing does not record reads by default. Then rebuild the model: table permissions with the narrowest access type (Contact, Account, Parent, Self, Global only for public reference data), child records scoped through a relationship to the signed-in contact, nothing sensitive on the Anonymous Users or Authenticated Users roles, and every permission tested as a real external user.
What should you do in the first hour after finding the leak?
Treat it as a security incident, not a bug ticket. The goal of the first hour is to stop further exposure without destroying the evidence you will need later, and to get the right people involved while the facts are still fresh. Do not start redesigning permissions yet. Redesign under pressure is how a second leak is created.
Write down, with times, what was seen, by whom, on which page, signed in as which contact, and screenshot it. Then contain in the order below, starting with the narrowest change that stops the exposure. Each step can be reversed once the correct model is in place.
| Containment step | How | What it stops |
|---|---|---|
| 1. Remove the page from reach | Unpublish the page or restrict it with page permissions to a web role nobody external holds, remove it from navigation, and switch off the OData feed on any list that renders the table. | Browsing to the list or form that showed the data, including by a bookmarked URL. |
| 2. Remove or narrow the table permission | Deactivate the table permission that grants the read, or remove the web role from it. Do not edit the scope in place yet, so the original is preserved as evidence. | The same data surfacing through another list, form or Liquid query that uses the same permission. |
| 3. Switch off the Web API for the table | Set the Webapi/<table>/enabled site setting to false, or deactivate it, for every affected table. | Direct calls to the portal Web API, which do not need a visible page at all. |
| 4. Clear the site cache | Clear the server cache from the site administration so configuration changes apply immediately rather than after the cache expires. | Users continuing to see stale results for a period after the fix. |
| 5. Verify as an external user | Sign in with a test contact from a different account in a private browser window and repeat what the reporter did, including the Web API call. | The false confidence of checking as a maker or administrator. |
| 6. Escalate the whole site if unsure | If you cannot tell which permission is responsible, restrict or take down the site until you can. | Guessing while the exposure continues. |
How do you find which permission is exposing the records?
A user's effective access in Power Pages is the combination of every table permission attached to every web role that user holds. Permissions add up; there is no deny. So the question is never "which permission is wrong" in isolation but "which of the permissions this contact receives grants read on this table without a narrow scope". Work through it systematically rather than by instinct.
- List the web roles the affected contact holds, and add the built-in role flagged as the Authenticated Users role, because every signed-in contact receives it whether or not it is assigned on the contact record.
- For each of those roles, list the table permissions on the exposed table and on any parent table the exposed records are reached through.
- Look first for Global access type on that table. Global read on a table of customer records attached to any role an external user holds is a common cause.
- Check Account access type where contacts are linked to the wrong parent account, or where one shared account holds contacts from several real companies, such as a generic "Individuals" account.
- Check Parent permissions whose parent permission is itself too broad: a child permission is only as narrow as the parent it hangs from.
- Check every list and basic or multistep form that renders the table and confirm table permissions are enabled on it, and check whether the list has its OData feed enabled. Older sites could be configured with lists that did not enforce table permissions, and list OData feeds on such sites were a known route to public data exposure.
- Check Liquid templates that query the table with fetchxml, and the Webapi/<table>/enabled and Webapi/<table>/fields site settings.
- Run the Power Pages security scan and site checker in the design studio, or the portal checker on older sites, and keep the output: it is useful evidence of what you checked and when.
Can the logs prove who actually viewed the exposed records?
Often only partly, and you should say so plainly to the DPO and the auditor rather than overstate certainty. Dataverse auditing, where it is enabled, records creates, updates and deletes; it does not record which portal visitor read which row by default. So the audit log alone will rarely show that customer A opened customer B's case.
What you can usually establish is a combination of: when the faulty permission or list was created or changed (from the configuration records and their modified dates, and from solution history if the change came through a deployment), who signed in during that window (from your identity provider sign-in logs, such as Microsoft Entra External ID), and, if it was already configured, request level telemetry from Application Insights or site diagnostic logging showing which pages and Web API endpoints were requested by which session. If none of that telemetry was in place, the honest statement is that access was possible for a defined set of users over a defined period, and that individual reads cannot be proven or ruled out.
| Source | What it can show | What it cannot show |
|---|---|---|
| Table permission, web role and list records | When the faulty configuration was created or last modified, and by which maker. | Which users exploited it. |
| Dataverse audit log | Changes to permissions, roles and contact web role assignments, if auditing was on for those tables. | Reads of the exposed records by portal users. |
| Identity provider sign-in logs | Which external users signed in, and when, during the exposure window. | What they looked at after signing in. |
| Application Insights or diagnostic logs, if enabled beforehand | Requests to the affected pages and Web API endpoints, by time and session. | Anything from before logging was switched on; enabling it now does not recover the past. |
Who needs to be involved, and what should you record?
Bring in your data protection officer or privacy lead on the first day. Whether an incident is notifiable, to whom, and on what timeline is a legal judgement for them and your advisers, and the timelines under regimes such as GDPR can be short. This page is technical guidance, not legal advice. What the technical team owes them is a clear, dated record they can rely on.
- A timeline: when the configuration was introduced, when the exposure was discovered, each containment step with its time, and when verification as an external user confirmed it was closed.
- Scope: the tables and columns exposed, the web roles and therefore the population of users who could reach them, and the period.
- The evidence from the previous section, including an explicit statement of what the logs cannot prove.
- Root cause in one paragraph: which permission, which access type, why it passed testing.
- The corrected model and the test evidence that it now behaves correctly for each role.
- The change to the release process that stops a repeat, such as a permission review and multi-account test before every deployment.
Which table permission access type should each table use?
The access type decides which rows a permission grants. Choose the narrowest one that lets the journey work, and give each permission only the privileges it needs: read, write, create, delete, append and append to are separate choices, and a read-only status page needs read and nothing else. The scopes and how they fit the portal route decision are summarised on our Power Pages or custom front end comparison; the table below is the leak-focused version.
| Access type | Grants rows that are | Use it for | Leak risk when misused |
|---|---|---|---|
| Global | All rows in the table, regardless of who is signed in. | Genuinely public or shared reference data: product catalogues, service categories, published knowledge. | Highest. Global read on customer data exposes every customer to anyone holding the role. |
| Contact | Related to the signed-in contact through a relationship you choose. | Records that belong to one person: their own cases, applications, registrations. | Low, if the relationship is the right one. |
| Account | Related to the parent account of the signed-in contact through a relationship you choose. | Company level data a customer or partner administrator should see across colleagues: orders, contracts, all cases for their company. | Medium. Exposes data across companies when contacts are linked to the wrong or a shared account. |
| Parent | Related to rows the user can already reach through a parent permission. | Child records: case notes, order lines, documents attached to an application. | Inherits the parent. A Parent permission under a Global parent is effectively Global. |
| Self | The contact row of the signed-in user (or, for accounts, their own account). | Profile pages where people update their own details. | Low. |
How do you scope child records to the signed-in contact?
Child records should never have their own Global permission. Build a chain instead: a Contact or Account permission on the parent table, then a Parent permission on each child table that follows the relationship from child to parent. A portal user then reaches a case note only because they can reach the case, and they reach the case only because it is linked to them or their account.
Three details catch teams out. First, the relationship matters: a case may relate to a contact through the customer column and through a separate primary contact column, and scoping on the wrong one shows people cases they are merely mentioned on. Second, creating a child from the portal needs append on the child and append to on the parent, so do not reach for Global to make a create form work. Third, where the data model has no relationship to the contact or account at all, the fix is a data model change, not a wider permission. The internal security model behind those same tables, for staff rather than portal users, is covered in Dynamics 365 security with business units and teams.
How do web roles and the built-in Anonymous Users and Authenticated Users roles cause accidental exposure?
Web roles group permissions and are assigned to contacts. Two built-in roles are different: the role flagged as the Anonymous Users role applies to every visitor who has not signed in, and the role flagged as the Authenticated Users role applies to every signed-in contact automatically. Neither needs to be assigned to anyone. A permission attached to either one is therefore granted to the whole public, or to every customer and partner with an account.
- A Global read added to the Authenticated Users role "temporarily" to make a list work during build, and never removed.
- A permission attached to the Anonymous Users role for a public page, on a table that also holds private rows. Anything granted anonymously should be treated as public to everyone.
- A partner administrator role with Account access type given to all partner contacts by default through the Authenticated Users role.
- Page permissions used as the only protection. Hiding a page does not protect the data if a table permission grants it and the Web API or another page exposes the table.
- Contacts invited into a shared or placeholder account, so Account access type joins unrelated people together.
- Roles copied from a template or a previous site without reviewing what they grant.
How do you test table permissions as a real portal user rather than as an admin?
Makers and administrators see the site differently from customers, and a single test account sees only one side of every boundary. A permission test proves nothing unless someone who should not see a row has tried and failed. Build a small test matrix and run it before every release that touches the data model, a web role or a permission.
- Create test contacts in at least two different accounts, plus one contact with no account, and one for each web role that exists.
- Seed each account with records of every exposed table and child table, with recognisable names so a leak is obvious on sight.
- Sign in as each test contact in a private browser window and walk every list, form, detail page and search.
- Change record IDs in URLs by hand to request another account's records directly.
- Call the Web API endpoints for each enabled table, for example /_api/ followed by the table's entity set name, while signed in as each contact, and while signed out.
- Record the expected and actual result per role and table, and keep the matrix as release evidence for the auditor.
How do you stop it happening again?
Leaks come from the process as much as from one permission. Make the correct model the easy path: table permissions and web roles designed with the data model before page design, reviewed in the same pull request as the page that uses them, and moved through environments in solutions rather than recreated by hand in production. Our delivery plan for a Power Pages launch under a fixed date puts permissions in the first weeks for exactly this reason.
Add the security scan and the multi-account test matrix to release sign off, keep Web API site settings limited to the tables and columns a page genuinely calls, and schedule a periodic review of role assignments and permissions. A wider independent look at security roles, configuration and ALM across the environment is what our Dynamics 365 health check and technical audit is for.
Is Power Pages still the right platform after a data leak?
Usually yes. The platform enforced exactly what it was configured to enforce, and a correctly scoped permission model is a sound basis for a customer portal. A leak is a reason to fix the configuration and the release process, not automatically to rebuild. The exception is when the data model cannot express who owns what, or when the portal has grown into a product experience the platform is straining to deliver.
We recommend the right solution - whether that's Microsoft Dynamics 365, Power Platform, or a custom-built CRM. Some businesses need the Microsoft ecosystem. Others need full control without licensing. We deliver both. Where Microsoft licensing or hosting requirements do not fit the portal, a custom-built CRM and portal on React, Node.js, PostgreSQL or .NET, with its own access model, is the alternative.
Should your customer portal run on Power Pages or on a custom platform you own?
Can afford licensing and want the Microsoft ecosystem
Dynamics 365
Microsoft 365, Teams and Outlook integration, a mature partner ecosystem, Copilot, and apps for sales, service and field operations that are configured rather than built.
Need full control and zero licensing
Custom CRM
A CRM built on React, Node.js, PostgreSQL or .NET that you own outright: your data model, your hosting, no per-user subscription, and features shaped exactly to your process.
Not sure which fits
We help you decide
A short discovery weighs licensing budget, process complexity, integrations and long-term ownership, then recommends one path. We deliver both, so the recommendation has no reason to lean.
How does Solzet help with a Power Pages permissions incident?
We work in the order of this page. First containment alongside your team, with each change logged and reversible. Then the exposure analysis from the configuration history, sign-in logs and any telemetry you had, written so your DPO can use it and honest about what cannot be proven. Then the corrected permission model, the multi-account test matrix and the evidence pack for the auditor, followed by the release process changes that keep it correct.
The Power Pages build work itself, from identity to Liquid and PCF controls in portal forms, is described in our Power Platform development service. Solzet delivers remotely from Yerevan, Armenia, with senior consultants and full-stack developers and 8+ years of Dynamics 365 Customer Engagement and Power Platform work, directly or white-label for Microsoft partners.
What do people ask us?
Why can a Power Pages customer see other customers' records?
Almost always because a table permission grants read with too broad an access type to a web role the customer holds. The usual causes are Global access on a customer table, Account access where contacts share the wrong parent account, a Parent permission under a broad parent, or a permission attached to the built-in Authenticated Users role, which every signed-in contact receives. A list without table permissions enabled, or an open Web API setting, can expose data too.
What should we switch off first when Power Pages is exposing data?
Restrict or unpublish the page and list showing the data, deactivate the table permission granting the read rather than editing it, set the Webapi site setting for the affected table to disabled, and clear the site cache so the changes apply at once. Then sign in as a test contact from another account and confirm the data is no longer reachable through pages, URLs or the Web API.
Does the Dataverse audit log show which portal users viewed a record?
Not by default. Dataverse auditing records creates, updates and deletes, not reads by portal visitors. You can usually establish when the faulty configuration was introduced and who signed in during that window, and page or Web API requests if Application Insights or diagnostic logging was already enabled. Without that telemetry, state honestly that access was possible for a defined group over a defined period, and involve your DPO.
What is the difference between Contact, Account and Parent access types in Power Pages?
Contact access grants rows related to the signed-in contact through a chosen relationship, such as their own cases. Account access grants rows related to the contact's parent account, such as every order for their company. Parent access grants child rows reached through a relationship from a row the user can already access through a parent permission, such as notes on their cases. Global grants every row and Self grants the user's own contact record.
Do permissions on the Authenticated Users web role apply to everyone?
They apply to every contact who signs in to the site, whether or not the role is assigned on their contact record. Permissions on the Anonymous Users role apply to every visitor who has not signed in, and anything granted that way should be treated as public. Keep both roles limited to genuinely shared reference data, and put customer data on assigned roles with narrow access types.
How should we test Power Pages table permissions before go live?
Create test contacts in at least two accounts and one for each web role, seed recognisable records for each, then sign in as each contact in a private browser window. Walk every list, form and detail page, edit record IDs in URLs, and call the Web API for each enabled table signed in and signed out. Record expected and actual results as release evidence, and never rely on testing as a maker or administrator.
Does the Power Pages security scan catch permission leaks?
It helps. The security scan and site checker in the design studio, and the portal checker on older sites, flag risky configuration such as broad permissions and settings that expose data. They cannot know which rows each of your customers should see, so they do not replace a data model review and a test matrix run as real external users from different accounts.
Where should you go next?
Power Platform development, including Power Pages
What a Power Pages build covers: journeys, identity, table permissions and web roles, Liquid, PCF controls and ALM.
Dynamics 365 health check and technical audit
An independent review of security, configuration, performance and ALM with evidence for every finding.
Customer portal: Power Pages or custom front end
Guest accounts, Power Pages or a React front end compared on licensing, identity, residency and access review.
Dynamics 365 security: business units and teams
The internal Dataverse security model behind the same tables your portal exposes.
Power Pages 90 day delivery plan
How to launch a Power Pages channel under a fixed date with permissions designed first.
Custom CRM Development
CRM and portals on React, Node.js, PostgreSQL and .NET for organizations that need full control without Microsoft licensing.
Which solution is right for your business?
Tell us what you need. A senior consultant replies within one business day with a recommendation - Dynamics 365, Power Platform, or a custom-built CRM - not a sales script.