For two decades, identity and access management programs have been built around a single assumption: the privileged user is a person. Domain admins, DBAs, finance approvers, and contractors with VPN access all sit inside a mature playbook — verified identity, least-privilege scoping, full activity logging, and a kill switch that revokes everything in minutes. That playbook works because humans can be interviewed, background-checked, trained, and held accountable.
AI agents break that assumption completely. As Rapid7's recent analysis puts it, your next insider threat won't be human. Agents are already reading mailboxes through Microsoft Graph, querying data lakes, opening and closing tickets, pushing code to repositories, and executing actions against production systems — often under service principals or OAuth grants that were approved once and never revisited. They operate at machine speed, 24/7, with access scopes that would trigger a change-control board review if a human requested them. And the industry's emerging consensus is the critical insight here: the controls on an AI agent cannot live inside the agent. A prompt-level instruction telling an agent not to exfiltrate data is a suggestion, not a control. Guardrails that execute inside the model's context window can be overridden by prompt injection, poisoned tool outputs, or a compromised orchestration layer.
This post is the defensive companion to that reality: what an outside-in control architecture looks like, what your SOC should be hunting today, and how to build detection and revocation capability for non-human identities before an agent becomes the vector for your next breach.
Technical Analysis: Why Internal Guardrails Fail and What Breaks First
The Threat Model
An AI agent is, from a security architecture standpoint, a privileged workload with three dangerous properties:
-
Broad delegated authority. Most enterprise agents are deployed with OAuth consent grants or service principal credentials carrying scopes like
Mail.Read,Files.Read.All,Sites.Read.All, or write access to CI/CD pipelines and ticketing systems. In our IR casework across 2025 and into 2026, the single most common finding in agent-related incidents is over-scoped application permissions granted at proof-of-concept time and never tightened for production. -
Manipulable decision-making. Prompt injection — direct or indirect via poisoned emails, documents, web pages, or tool responses — remains an unsolved problem. An agent that reads your mailbox can be instructed by the mailbox to forward its contents. If the only thing standing between that instruction and execution is a system prompt, you have no control at all.
-
Speed and scale. A compromised or misbehaving agent doesn't exfiltrate one file. It iterates across every mailbox, SharePoint site, or data lake table its token can reach, at API speed, generating thousands of anomalous-but-technically-authorized calls.
Why Controls Must Be External
The Rapid7 piece frames this correctly: enforcement must live in infrastructure the agent cannot influence. In practice that means:
- Identity layer (control plane). Every agent gets its own non-human identity — a dedicated service principal or managed identity in Entra ID, an IAM role in AWS/GCP — never shared human credentials, never a shared app registration across agents.
- Scoped, just-in-time authorization. Application permissions replaced with delegated, time-boxed, resource-scoped access wherever the platform supports it. An agent that summarizes unread mail does not need
Mail.ReadWriteon all mailboxes. - Egress and API policy enforcement. Agents should reach model endpoints and data APIs through a gateway or proxy that enforces allowlists, rate limits, and payload inspection — controls that exist regardless of what the agent's prompt says.
- Independent logging and revocation. Token issuance, API calls, and tool invocations logged to a SIEM the agent cannot write to, with a documented revocation runbook that can kill credentials, disable the principal, and invalidate sessions in under 15 minutes.
Exploitation Status
This is not a theoretical exposure. Throughout 2025 and early 2026, threat actors and red teams alike have demonstrated indirect prompt injection against production copilots and agent frameworks, OAuth consent phishing as a persistence and mailbox-access mechanism, and abuse of over-permissioned service principals for data theft. No single CVE defines this threat class — it is an architectural exposure spanning identity, API authorization, and model behavior. CISA and vendor guidance increasingly treat non-human identities as first-class attack surface, and defenders should too.
Detection & Response
The detections below target the observable behaviors that matter: anomalous consent grants, service principal credential manipulation, shadow-AI egress, and agent processes behaving like tools of exfiltration. Tune thresholds against your known agent inventory first — a detection you can't tell apart from your sanctioned agents is noise.
Sigma Rules
---
title: High-Risk OAuth Consent Grant to Application
tech_id: 9b2c4e71-3a8f-4d1c-b6e5-7f0a2c8d4e91
id: 9b2c4e71-3a8f-4d1c-b6e5-7f0a2c8d4e91
status: experimental
description: Detects OAuth consent grants assigning broad mail, file, or directory scopes to an application — a common path for AI agent over-permissioning and consent-phishing persistence.
references:
- https://attack.mitre.org/techniques/T1550/001/
- https://www.rapid7.com/blog/post/ai-inhuman-insider-threats-securing-agents
author: Security Arsenal
date: 2026/04/06
tags:
- attack.credential_access
- attack.t1550.001
- attack.persistence
logsource:
product: azure
service: auditlogs
detection:
selection:
operationName: 'Consent to application'
filter_scopes:
targetResources|contains:
- 'Mail.Read'
- 'Mail.ReadWrite'
- 'Mail.Send'
- 'Files.Read.All'
- 'Files.ReadWrite.All'
- 'Sites.Read.All'
- 'Directory.Read.All'
- 'offline_access'
condition: selection and filter_scopes
falsepositives:
- Sanctioned enterprise agent deployments — maintain an allowlist of approved app IDs and re-alert on anything outside it
level: high
---
title: Credentials Added to Existing Service Principal
id: 4f8a1d63-7c2b-4e59-a1d8-3b6f9c0e2a47
status: experimental
description: Detects addition of passwords or certificates to an existing app registration or service principal, a technique used to backdoor AI agent identities and maintain persistent API access.
references:
- https://attack.mitre.org/techniques/T1098/001/
- https://www.rapid7.com/blog/post/ai-inhuman-insider-threats-securing-agents
author: Security Arsenal
date: 2026/04/06
tags:
- attack.persistence
- attack.t1098.001
logsource:
product: azure
service: auditlogs
detection:
selection:
operationName:
- 'Add service principal credentials'
- 'Update application - Certificates and secrets management'
- 'Add password to service principal'
falsepositives:
- Routine secret rotation by automation — correlate with change tickets and rotation schedules
level: high
---
title: Server Workload Egress to Public LLM API Endpoints
id: 6d3e9b08-2f47-4a1c-9b52-8e1d6a0c5f73
status: experimental
description: Detects processes on server workloads initiating outbound TLS connections to public LLM provider APIs, indicating unapproved AI agent deployment (shadow AI) or agent-driven data egress.
references:
- https://attack.mitre.org/techniques/T1567/002/
- https://www.rapid7.com/blog/post/ai-inhuman-insider-threats-securing-agents
author: Security Arsenal
date: 2026/04/06
tags:
- attack.exfiltration
- attack.t1567.002
logsource:
category: network_connection
product: windows
detection:
selection:
DestinationHostname|contains:
- 'api.openai.com'
- 'api.anthropic.com'
- 'generativelanguage.googleapis.com'
- 'api.mistral.ai'
- 'openai.azure.com'
filter_browser:
Image|endswith:
- '\msedge.exe'
- '\chrome.exe'
- '\firefox.exe'
filter_approved_agents:
Image|endswith:
- '\approved-agent-host.exe'
condition: selection and not 1 of filter_*
falsepositives:
- Developer workstations and sanctioned copilot integrations — scope this rule to server OUs and maintain an approved-agent binary list
level: medium
KQL Hunt — Microsoft Sentinel / Defender
The following query hunts for anomalous service principal behavior consistent with a compromised or misbehaving AI agent: bursts of Graph API reads against mail and files, new consent grants, and credential additions — correlated per application over a rolling window.
let Lookback = 14d;
let Baseline = 30d;
let HighRiskScopes = dynamic(["Mail.Read","Mail.ReadWrite","Files.Read.All","Sites.Read.All","Directory.Read.All","Mail.Send"]);
// Part 1: New high-risk consent grants or credential additions in the lookback window
AuditLogs
| where TimeGenerated > ago(Lookback)
| where OperationName in~ ("Consent to application","Add service principal credentials","Update application – Certificates and secrets management")
| mv-apply TargetResource = TargetResources on (
where TargetResource.displayName has_any (HighRiskScopes) or OperationName has "credentials"
)
| extend AppId = tostring(TargetResources[0].id),
Actor = tostring(InitiatedBy.user.userPrincipalName),
IPAddr = tostring(InitiatedBy.user.ipAddress)
| summarize RiskEvents = count(), Operations = make_set(OperationName) by AppId, Actor, IPAddr, bin(TimeGenerated, 1h)
| where RiskEvents >= 1
| join kind=leftouter (
// Part 2: Baseline check — is this app historically present and active?
SigninLogs
| where TimeGenerated > ago(Baseline)
| summarize HistoricalSignins = count() by AppId
) on AppId
| extend IsNewPrincipal = (HistoricalSignins < 10 or isempty(HistoricalSignins))
| project TimeGenerated, AppId, Actor, IPAddr, Operations, RiskEvents, HistoricalSignins, IsNewPrincipal
| sort by IsNewPrincipal desc, TimeGenerated desc
// Part 3: Hunt for machine-speed mailbox/file access patterns from non-human identities
let Threshold = 500;
OfficeActivity
| where TimeGenerated > ago(24h)
| where Operation in~ ("MailItemsAccessed","FileAccessed","FileDownloaded","SearchQueryPerformed")
| where UserType in ("ServicePrincipal","Application") or UserId contains "app@"
| summarize AccessCount = count(), DistinctTargets = dcount(OfficeObjectId), Workloads = make_set(OfficeWorkload)
by UserId, ClientIP, bin(TimeGenerated, 15m)
| where AccessCount > Threshold or DistinctTargets > 100
| project TimeGenerated, UserId, ClientIP, AccessCount, DistinctTargets, Workloads
| sort by AccessCount desc
Velociraptor VQL — Endpoint Hunt for Agent Processes
Use this artifact to enumerate processes holding active connections to LLM endpoints or AI orchestration frameworks, and to identify binaries running from non-standard paths — useful for scoping shadow-AI deployments across a fleet.
-- Hunt: processes with live connections to public LLM APIs or local agent runtimes
SELECT Pid, Ppid, Name, CommandLine, Exe, Username,
Connections.remote_ip AS RemoteIP,
Connections.remote_port AS RemotePort
FROM pslist()
WHERE CommandLine =~ '(?i)(openai|anthropic|langchain|autogen|crewai|llamaindex|semantic.?kernel|ollama|mcp.?server)'
OR Exe =~ '(?i)(ollama|llama|agent|copilot)'
OR Pid IN (
SELECT Pid FROM netstat()
WHERE Status =~ 'ESTABLISHED'
AND RemotePort in (443, 11434)
AND RemoteIP =~ '^(?!10\\.|192\\.168\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.)'
)
-- Hunt: agent binaries executing from user-writable or temp paths (non-standard install)
SELECT Pid, Name, Exe, CommandLine, Username, CreateTime,
hash(path=Exe).SHA256 AS SHA256
FROM pslist()
WHERE Exe =~ '(?i)(\\\\Users\\\\[^\\]+\\\\(AppData|Downloads|Desktop)\\\\|\\\\Temp\\\\|\\\\ProgramData\\\\)'
AND CommandLine =~ '(?i)(python|node|agent|mcp|llm|graph|mail)'
Remediation & Audit Script — Entra ID Service Principal Hygiene
This PowerShell script inventories application consent grants with high-risk scopes, flags service principals with recently added credentials or no sign-in governance, and exports a revocation candidate list. Run it with a Global Reader or Privileged Role Administrator context via Microsoft Graph PowerShell.
# Requires: Microsoft.Graph PowerShell SDK, scopes: Application.Read.All, AuditLog.Read.All
# Purpose: Inventory high-risk OAuth grants and flag revocation candidates for AI-agent identities
Connect-MgGraph -Scopes "Application.Read.All","AuditLog.Read.All","Directory.Read.All" -NoWelcome
$HighRiskScopes = @("Mail.Read","Mail.ReadWrite","Mail.Send","Files.Read.All","Files.ReadWrite.All","Sites.Read.All","Directory.Read.All","ChannelMessage.Read.All")
$ReportPath = ".\AgentIdentityAudit_$(Get-Date -Format 'yyyyMMdd_HHmm').csv"
# --- 1. Enumerate all OAuth2 permission grants and match against high-risk scopes ---
$Grants = Get-MgOauth2PermissionGrant -All
$Flagged = foreach ($g in $Grants) {
$matched = ($g.Scope -split ' ') | Where-Object { $HighRiskScopes -contains $_ }
if ($matched) {
$sp = Get-MgServicePrincipal -ServicePrincipalId $g.ClientId -ErrorAction SilentlyContinue
[PSCustomObject]@{
AppDisplayName = $sp.DisplayName
AppId = $sp.AppId
ServicePrincipal = $g.ClientId
ConsentType = $g.ConsentType # 'AllPrincipals' = tenant-wide admin consent
RiskScopes = ($matched -join ';')
CreatedDateTime = $sp.CreatedDateTime
Action = if ($g.ConsentType -eq 'AllPrincipals') { 'REVIEW-REVOKE-CANDIDATE' } else { 'REVIEW' }
}
}
}
# --- 2. Flag service principals with credentials added in the last 30 days ---
$Cutoff = (Get-Date).AddDays(-30)
$RecentCreds = foreach ($sp in (Get-MgServicePrincipal -All -Property "DisplayName,AppId,KeyCredentials,PasswordCredentials")) {
$newKeys = @($sp.PasswordCredentials | Where-Object { $_.StartDateTime -gt $Cutoff }) +
@($sp.KeyCredentials | Where-Object { $_.StartDateTime -gt $Cutoff })
if ($newKeys.Count -gt 0) {
[PSCustomObject]@{
AppDisplayName = $sp.DisplayName
AppId = $sp.AppId
NewCreds30d = $newKeys.Count
Action = 'VERIFY-AGAINST-CHANGE-TICKET'
}
}
}
# --- 3. Output and guidance ---
$Flagged + $RecentCreds | Export-Csv -Path $ReportPath -NoTypeInformation
Write-Host "`n[*] $($Flagged.Count) high-risk consent grants | $($RecentCreds.Count) principals with recent credentials" -ForegroundColor Yellow
Write-Host "[*] Report: $ReportPath`n"
Write-Host "Revocation runbook (execute only after business-owner confirmation):" -ForegroundColor Cyan
Write-Host ' # Revoke all refresh tokens / sessions for a principal:'
Write-Host ' Revoke-MgServicePrincipalSignInSession -ServicePrincipalId <SP_ID>'
Write-Host ' # Remove a specific over-scoped grant:'
Write-Host ' Remove-MgOauth2PermissionGrant -OAuth2PermissionGrantId <GRANT_ID>'
Write-Host ' # Disable the principal entirely (kill switch):'
Write-Host ' Update-MgServicePrincipal -ServicePrincipalId <SP_ID> -AccountEnabled:$false'
Remediation: The Outside-In Control Stack
Prioritize in this order — each layer works even if the ones above it fail:
-
Inventory every non-human identity this week. Most organizations cannot list their AI agents, let alone their scopes. Run the audit script above, pull your full service principal and OAuth grant inventory from Entra ID / Okta / your cloud IAM, and reconcile it against a business-owner-approved agent register. Anything unowned gets disabled pending review.
-
Enforce least privilege at the identity layer. Replace tenant-wide admin consent (
AllPrincipals) with user-scoped or resource-specific consent. In Microsoft 365, migrate from broad application permissions to Application Access Policies (New-ApplicationAccessPolicy) that restrict Graph access to specific mailboxes. In cloud environments, scope agent IAM roles to specific buckets, tables, and queues — never wildcard actions on wildcard resources. -
Move secrets out of reach. Eliminate long-lived client secrets on agent identities. Use managed identities, workload identity federation, or certificate-based auth with automated rotation. Set credential lifetime ceilings and alert on any secret older than 90 days.
-
Put a policy-enforcing gateway between agents and everything else. Route all agent traffic — model calls, tool invocations, API access — through an AI gateway or forward proxy that enforces allowlisted destinations, rate limits, and DLP inspection. An agent instructed via prompt injection to POST mailbox contents to an external host should fail at the egress layer, not at the model's discretion.
-
Implement human-in-the-loop gates for irreversible actions. Production changes, code merges, financial transactions, and mass communications initiated by agents must require a human approval step enforced by the orchestration platform — not by instructions in the system prompt.
-
Build and drill the revocation runbook. Your IR plan needs a dedicated playbook for non-human identity compromise: disable principal, revoke sessions and refresh tokens, rotate or remove credentials, invalidate cached agent state, and audit all API activity for the token's lifetime. Drill it quarterly. Target under 15 minutes from decision to full revocation.
-
Log everything to infrastructure the agent can't touch. Enable and centralize Entra audit logs, Graph activity logs, Office 365 unified audit log (
MailItemsAccessedis essential), and gateway logs into your SIEM. Deploy the detections in this post and tune them against your approved-agent inventory. -
Treat agent supply chain as attack surface. Agent frameworks, MCP servers, tool plugins, and model providers are third-party code with your credentials. Vet them, pin versions, monitor for updates, and apply the same vendor-risk rigor you'd apply to any software with production access.
The organizations that get this right will treat AI agents exactly like the privileged users they are — except with tighter controls, because agents can't exercise judgment, can't notice they're being manipulated, and can't be trained not to click. The controls have to live outside of them. Build that perimeter now, while your agent footprint is still small enough to inventory.
Related Resources
Security Arsenal Penetration Testing Services AlertMonitor Platform Book a SOC Assessment vulnerability-management Intel Hub
Is your security operations ready?
Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.