PathixDataverse Forensics
The findings library

What Pathix checks for.

23 deterministic security findings, each mapped to specific SOC 2, ISO 27001:2022, and NIST 800-53 controls, plus 17 operational findings for environment health. Every one is read from your real customization graph, plugins, roles, flows, and field security, and scored per instance in your own environment.

23
SECURITY FINDINGS
17
OPERATIONAL FINDINGS
SOC 2 · ISO 27001 · NIST
CONTROL MAPPINGS
See these in the live demoHow findings work
Access & least privilege 8Identity lifecycle & offboarding 5Data protection & field security 4Auditability & observability 2Secrets & transmission security 4Integration & automation reliability 15Platform currency 2
Security findings · control-mapped

23 findings that map to a specific control.

Each of these is a condition Pathix detects deterministically and maps to SOC 2, ISO 27001:2022, and NIST 800-53. The mappings are indicative: Pathix detects a condition relevant to a control, it does not certify your compliance, and a finding is not an audit opinion. You stay responsible for your control environment.

ACCESS & LEAST PRIVILEGE

Who really holds what, and where a change or a stolen credential quietly widens access, including the self-elevation paths.

Security role assigned to both human users and integrations

SOC 2 CC6.3ISO 27001 A.5.15 / A.5.18NIST AC-5 / AC-6

One role held by both people and service accounts means every privilege you add hits both audiences at once, and a stolen integration key inherits full human access.

Fix. Split the role in two: humans on one copy, integrations on the other.

Integration account holds a Microsoft system role

SOC 2 CC6.1 / CC6.3ISO 27001 A.8.2NIST AC-6 / AC-6(5)

A service account with System Administrator or System Customizer bypasses nearly every access check. A compromised key can read everything, rewrite security, and cover its tracks. Pentesters find this in the first fifteen minutes.

Fix. Replace the system role with a custom least-privilege role scoped to what the integration actually touches.

Integration can rewrite the security model

SOC 2 CC6.3ISO 27001 A.8.2NIST AC-6(1) / AC-3

A service account whose role can create roles, assign roles, or provision users can bootstrap itself to full control through the API alone. No production integration needs this.

Fix. Remove the security-metadata write privileges; put any genuine user management behind human approval.

Human user holds a role that can rewrite the security model

SOC 2 CC6.3ISO 27001 A.8.2NIST AC-6(1) / AC-6(10)

A non-admin whose custom role grants role or user administration can grant themselves anything through the API: a low-privilege login that can bootstrap itself to full control.

Fix. Remove those privileges, reserve admin for named people, and turn on prevent-elevation-of-privilege.

Team mixes human members and integrations while holding roles

SOC 2 CC6.3ISO 27001 A.5.15 / A.5.18NIST AC-5 / AC-6

A role-holding team with both people and service accounts as members grants every privilege to both, the same shared-role risk arriving through team membership, where the direct check cannot see it.

Fix. Move integrations onto a dedicated team with its own least-privilege role.

Business unit default team holds a security role

SOC 2 CC6.1ISO 27001 A.5.15 / A.8.2NIST AC-6 / AC-2

Every user in a business unit is an unremovable member of its default team, so a role there grants to the whole unit and widens automatically as people are added. Easy to do by accident.

Fix. Move the role onto an owner team or an explicit assignment naming only the users who need it.

Custom role grants act on behalf of another user

SOC 2 CC6.1 / CC6.3ISO 27001 A.8.2NIST AC-6 / AU-10

The delegation privilege lets a principal act as another user, attributing their actions to someone else and operating with that user's access. Legitimate for some integrations, worth confirming for the rest.

Fix. Confirm each holder needs it, scope it to a dedicated integration identity, and remove it elsewhere.

No operational role grants the required privilege

SOC 2 CC6.1ISO 27001 A.8.3NIST AC-3

A plugin step runs on a CRUD message against a table whose privilege no operational role grants, so least-privilege users hit access errors and the step does not execute. A functional-coverage gap, not over-privilege.

Fix. Add the missing privilege to a role the users already hold, custom or out-of-the-box.

IDENTITY LIFECYCLE & OFFBOARDING

The canonical "termination did not fully revoke" family: every residual path a disabled account leaves behind. Pathix's strongest single compliance story.

Disabled user account still has security role assignments

SOC 2 CC6.2ISO 27001 A.5.18NIST AC-2 / PS-4

Disabling a user suspends login but keeps their roles. Re-enable the account, on purpose or through a directory sync, and every role snaps back with no further action.

Fix. Strip roles during offboarding; re-grant on reactivation only after review.

Disabled user account still holds manually shared records

SOC 2 CC6.2ISO 27001 A.5.18NIST AC-2 / AC-21 / PS-4

Disabling a user revokes neither roles nor record shares, and shares have no surface in the user UI, so they survive careful offboarding. Re-enable the account and the shared records are reachable again.

Fix. Revoke manual shares alongside role removal, or reassign the records to a team.

Enabled automation is owned by a disabled user account

SOC 2 CC6.2ISO 27001 A.5.18NIST AC-2 / PS-4

A live flow or workflow owned by a disabled account authenticates and runs under that owner, so it stalls or refuses reactivation, and the process it drove silently stops.

Fix. Reassign to a service account, re-test its connections, and add reassignment to offboarding.

Plugin step impersonates a disabled user account

SOC 2 CC6.2ISO 27001 A.5.18NIST AC-2 / PS-4

A step set to always run as a disabled user fails every time it fires, because Dataverse cannot build a run-as context for a disabled principal.

Fix. Repoint the impersonation to an active service account, or remove it so the step runs as the caller.

Plugin step always runs as one fixed user account

SOC 2 CC6.1ISO 27001 A.8.15NIST AU-2 / AU-10

Every change the step makes is attributed to one account regardless of who triggered it, obscuring who really acted, and it breaks the day that account leaves.

Fix. Confirm the impersonation is intentional and points at a dedicated service account, not a person's login.

DATA PROTECTION & FIELD SECURITY

Where a field marked sensitive is misconfigured, exposed, or quietly copied past its own protection.

Secured column value lands in an unsecured column

SOC 2 CC6.1 / CC6.7ISO 27001 A.8.3 / A.5.12NIST AC-4 / SC-28

A field mapping or formula copies a secured value into an unsecured column, so anyone who can read the destination reads the protected value without a grant. An active leak of data you deliberately gated.

Fix. Secure the destination the same way or break the mapping, and clear values already copied.

Default view exposes a field-level-security secured column

SOC 2 CC6.1ISO 27001 A.8.3NIST AC-3 / AC-4

A secured column sits in the default view, so its header shows to everyone and rows without a grant render blank. Dataverse still enforces access, so this is a posture and UX gap, not a leak.

Fix. Remove the secured column from the default view; make a separate view for the audience that has the grant.

Form layout includes a field-level-security secured column

SOC 2 CC6.1ISO 27001 A.8.3NIST AC-3 / AC-4

Same problem on a form: users without the grant see a blank control that reads as broken rather than protected. Enforced server-side, so posture and UX, not exfiltration.

Fix. Remove the secured column from forms shown to audiences that lack the grant, or scope a form variant to those who have it.

Field-level security enabled but no profile grants access

SOC 2 CC6.1ISO 27001 A.8.3NIST AC-3

A column is secured but no field-security profile grants access, so it is unreachable in the UI and SDK. Users hit Access Denied mid-workflow. A functional gap, mapped lightly.

Fix. Grant the column through a profile and assign users, or turn field security off if it does not need protecting.

AUDITABILITY & OBSERVABILITY

Where a change to sensitive data, or a failure in the code that touches it, leaves no trace.

Sensitive column changes are not being audited

SOC 2 CC7.2ISO 27001 A.8.15NIST AU-2 / AU-12

Auditing a secured column needs the org, table, and column switches all on. If any is off, no history is written, so who changed a sensitive value and when cannot be reconstructed.

Fix. Turn on all three switches and set retention to match your compliance requirement.

Component catches exceptions without logging or rethrowing

SOC 2 CC7.2ISO 27001 A.8.15NIST AU-2 / SI-11

A plugin catch block that neither logs nor rethrows makes failures vanish with no trace. Read deterministically from the compiled IL; severity rises when the component writes a sensitive field.

Fix. Rethrow or trace the error before continuing; if swallowing is intended, say so in a trace line.

SECRETS & TRANSMISSION SECURITY

Credentials left in the open, and outbound calls or entry points that move data or accept traffic without protection.

Plugin step has a secret embedded in unsecure configuration

SOC 2 CC6.1ISO 27001 A.5.17 / A.8.24NIST IA-5 / SC-28

A credential sits in a plugin step's unsecure config, readable by anyone who can read the registration and carried into solution exports and source control. Pathix reports the pattern and a redacted length, never the value.

Fix. Move it to Azure Key Vault via an environment variable, and rotate the exposed credential.

Integration endpoint sends payloads over plaintext HTTP

SOC 2 CC6.7ISO 27001 A.8.24 / A.5.14NIST SC-8 / SC-13

A service endpoint or webhook uses http, so record data, execution context, and any credential in the message cross the network unencrypted.

Fix. Re-register against https, verify the certificate, and rotate any credential sent in the clear.

Webhook sends outbound calls with no authentication

SOC 2 CC6.1ISO 27001 A.8.3 / A.5.14NIST IA-9 / SC-8

A webhook with no key or header cannot prove its calls are genuine, so anyone who learns the URL can post traffic that looks authentic.

Fix. Add a header-based secret and require it at the receiver; rotate it periodically.

HTTP-triggered flow can be run by anyone with the URL

SOC 2 CC6.1ISO 27001 A.8.3NIST AC-3 / IA-2

The flow's trigger accepts anyone with the URL, no identity check, so a leaked link lets anyone drive whatever the flow does in Dataverse. Power Automate now defaults new flows to tenant-restricted.

Fix. Restrict the trigger to your tenant or named users, and regenerate the signature key so old URLs stop working.

Operational findings · environment health

17 findings that keep the environment healthy.

Broken, orphaned, looping, or wasteful automation, and surfaces built on retired platform pieces. Genuinely valuable, and often the reason a migration bid goes sideways, but they are not compliance-control findings. We keep them clearly separate so the security findings above keep their weight.

INTEGRATION & AUTOMATION RELIABILITY

Broken, orphaned, looping, or wasteful automation. Real environment-health value, but not evidence for a security control, and we label it that way on purpose.

Plugin step writes a column its own trigger filters on

Reliability

The step re-queues itself on every save, doubling side effects and burning depth budget. Only the platform's depth guard keeps it from an infinite loop.

Fix. Move the write to a PreOperation Target modification, or drop the column from the step's filter.

Tied plugin steps write the same column in undefined order

Correctness

Two steps on the same table, message, and stage share an execution order and write overlapping columns, so the final value is nondeterministic and can flip after a redeploy or import.

Fix. Give the steps distinct execution orders, placing the one that should win last.

Same plugin type registered twice on one message and stage

Correctness

The same plugin runs twice on every matching operation, doubling side effects and outbound calls for no benefit. A classic re-import artifact.

Fix. Unregister the duplicate, keeping the one with the correct configuration.

Update plugin step fires on every column change

Performance

No filtering attributes means the step runs on every update of every column, which autosave multiplies, spending compute and feeding re-trigger loops. Microsoft's guidance calls for filters on every Update step.

Fix. Register filtering attributes for only the columns the step reacts to.

Plugin step registered on Retrieve or RetrieveMultiple

Performance

These are the hottest messages on the platform, so every list view, lookup, and API read pays the step's cost. Worst when it makes an outbound call on every read.

Fix. Move the logic off the read path; if it must stay, keep it fast with no outbound calls or extra queries.

Dataverse flow trigger fires on every column change

Performance

An Update trigger with no selected columns runs on every column change, which autosave multiplies, spending run capacity and feeding re-trigger loops. The flow-plane version of an unfiltered Update step.

Fix. Set the trigger's Select columns to only the columns the flow reacts to.

Synchronous plugin step calls an outbound endpoint in the save transaction

Availability

A synchronous step routes to a webhook inside the user's save, so a slow or unreachable endpoint delays or fails every affected save. The same integration run asynchronously carries none of this risk.

Fix. Re-register the step asynchronously unless the caller truly needs the response before the save commits.

Connection reference has flows but no underlying connection

Availability

Flows cannot run through an unbound reference, so enabled ones fail at run time and disabled ones fail to activate. Common after an import skipped the connection wiring.

Fix. Bind the reference to a service-account connection and test each flow.

Modern flow has been suspended by the platform

Availability

The platform stopped the flow, usually a data-loss-prevention policy violation, so its business process silently stopped while the flow still appears configured. The DLP cause is a real governance signal.

Fix. Read the suspension reason, fix the connector or policy conflict, and resubmit for activation.

Asynchronous plugin step never purges completed jobs

Capacity

Successful async runs pile up in the system-job table without bound, slowing the async queue and consuming storage.

Fix. Turn on delete-on-success so completed jobs purge while failures stay for troubleshooting.

Plugin step targets a table outside the scanned metadata

Hygiene

A step is registered against a table Pathix could not resolve in the scan, so its writes and reads do not appear in dependency results. Often a deleted table with a stale registration.

Fix. Confirm the target exists and is in scope; unregister the step if the table was retired.

Flow action references a table Pathix could not resolve

Hygiene

A flow action targets a table Pathix could not match, so its writes and reads are missing from dependency results. Often an excluded entity or a mistyped name.

Fix. Confirm the action targets the table you expect; fix the target or bring the table into scope.

Connection reference with no flow binding

Hygiene

A connection reference exists but no flow binds to it. Not an active risk alone; the privileges of the underlying connection are the concern if it is ever re-bound.

Fix. Delete it if genuinely unused, and rotate any broad or secret-bearing connection underneath.

Service endpoint or webhook with no plugin step binding

Hygiene

An endpoint is registered but nothing triggers it. Not an active risk alone, but an over-permissioned or long-unused endpoint is worth cleaning up.

Fix. Delete it if unused and rotate any credential baked into its definition.

Pathix could not fully parse this component

Coverage

A component works in Dataverse but the parser could not extract its full structure, so its writes and reads are incomplete in results. We treat these as parser bugs, not environment problems, and surface them rather than hide the gap.

Fix. Report it with the component name; fixes land in the parser. Retire the component if it is unused.

PLATFORM CURRENCY

Surfaces built on connectors and controls the platform has retired or moved on from.

Connection reference uses a retired or deprecated connector

Currency

Flows on the retired Dynamics 365 connector no longer run; flows on the deprecated legacy Dataverse connector work on borrowed time with no fixes.

Fix. Recreate the connection on the current Dataverse connector and rebind each flow.

Form uses a control Microsoft has deprecated

Currency / a11y

A form declares a deprecated control (the older Flip Switch, slider, or knob controls) that gets no fixes or accessibility improvements and can break after a platform update.

Fix. Swap it for the modern equivalent (Toggle, number input, supported slider) and re-test the form.

See which of these are in your environment.

Every scan runs these checks against your real Dynamics customization graph, ranked by severity, each with the principals it exposes and the control it answers to.

Live demoBook a demo
Pathix

Forensics for Dynamics 365 and the Dataverse.

See it on sample data →
USE CASES
CAPABILITIES
  • What we check
  • Dataverse MCPsoon
  • Dependency analysissoon
  • Migration impactsoon
PRODUCT
COMPANY
© 2026 Pathix · self-hosted · metadata-onlyNot affiliated with Microsoft. Dynamics 365, Dataverse, and Power Platform are trademarks of Microsoft Corporation.