LowScript packFree

Copilot AI Governance

Findings for how AI agents, agent identities, and the Copilot agent catalog are governed in Microsoft 365: sponsor/owner coverage, unused agents and tools, assignment-group ownership, broad Graph write permissions on agent identities, unclear agent and blueprint names, classic Copilot Studio servic…

By chadmcox · Version 0.7.1 · Published 11 Nov 2026

← All tests

MP.AIGOV.1019 Agent identity should not have user-consented delegated permissions

Severity: MediumGraph

Lists agent identities via GET /servicePrincipals/microsoft.graph.agentIdentity (v1.0), then for each one calls GET /oauth2PermissionGrants?$filter=clientId eq '{agent identity object ID}' and consentType eq 'Principal' (v1.0) — clientId is the service principal's object ID, not its appId, and $filter on this endpoint only supports eq, confirmed against the oauth2PermissionGrant resource and "List oauth2PermissionGrants" Learn reference pages. consentType Principal means a single end user consented for themselves, as opposed to AllPrincipals (an administrator consented tenant-wide) — this test only reports the user-consented case, since an admin-consented grant is a deliberate, reviewed decision rather than an individual user's choice to grant an autonomous agent delegated access to their own data. Uses the least-privileged Graph permission confirmed on the "List oauth2PermissionGrants" reference page, Directory.Read.All (application).

Findings are grouped per agent identity: the number of distinct consenting users and the deduplicated set of granted scopes. An agent is Medium by default; High if any granted scope appears on Maester's own MT.1223 (Test-MtEntraAgentHighRiskGraphPermissions) high-risk permission list. That list was read directly from MT.1223's source (Get-MtEntraAgentHighRiskGraphPermissionFinding.ps1, pinned commit 616559854634e5150dbde69850c4224191635bb1 — the same commit this pack's Test-MtPack CI job builds Maester from) rather than re-derived from memory, so it tracks Maester's actual classification instead of a separate guess at what counts as high risk. That hashtable isn't exported from the module, so it is reproduced here verbatim with this citation; keep it in sync if MT.1223's source changes.

A Pester unit test (unit-tests/Test.MP.AIGOV.1019.Tests.ps1) pins a SHA-256 hash of the $HighRiskScopes array literal as a drift tripwire: if a future edit changes that array without a matching update to the pinned hash and the commit SHA cited above, the unit test fails rather than silently drifting from Maester's current classification.

An agent identity whose per-agent grant read fails (not a 403 on the initial list call, but a failure reading grants for one specific agent) is counted and excluded from the result rather than silently dropped or failing the whole test — the count is reported alongside a Pass or Fail outcome so a partial-evaluation result is never mistaken for a clean Pass.

[!NOTE] Validated 2026-11-06 against a real Microsoft 365 test tenant (F7-licensed). The run correctly Passed (true negative): 11 agent identities were checked and none had a user-consented (non-admin) delegated permission grant, so the High-severity path (a scope on MT.1223's high-risk list) was not exercised against real data this round.

Remediation action

Review each listed scope with the consenting user(s). If the access isn't intentional or necessary, revoke the grant. If any High-risk scope is present, treat it with the same urgency as MT.1223's application-permission findings.

Related links

%TestResult%

Install
Install-MtPack chadmcox/maester-ai-governance-pack/pack

Assumes Maester is installed. New to Maester? Get started.

Next: connect and run
Connect
Connect-Maester
Run
Invoke-Maester -Pack AIGOV