Shadow AI Detection: How to Hunt Unapproved AI Apps, Agents and API Use

Shadow AI Detection: How to Hunt Unapproved AI Apps, Agents and API Use

Ajmal Kohgadai
Ajmal Kohgadai
November 2, 2026

For about 11 hours on October 29, 2026, Cursor's extension marketplace served a tampered build of Anthropic's Claude Code extension, versions 2.1.312 and 2.1.313 for Windows and macOS. Once loaded, the extension added an attacker's SSH key to the user's authorized_keys file and started a reverse SSH tunnel to the attacker's server, according to Cursor's security notice. It also installed persistence that kept running after the extension was removed. On most hosts, the step that turns on the local SSH service failed for lack of admin rights. Cursor told customers to search endpoint, network and extension-installation telemetry for the published indicators. That search is quickest for a team that already knows which machines run Cursor and which extensions are installed on them.

Shadow AI detection is the practice of finding AI tools, agents and model API use that an organization has not approved or cannot see, across browser and SaaS use, connected apps, endpoints, and servers and cloud workloads. A list of AI domains in proxy logs finds browser chat that crosses the proxy. It shows little about the coding agents and CLIs that run commands and hold credentials on developer machines, or about the connected apps that read mail and files through OAuth grants. In its 2025 Cost of a Data Breach study, IBM found that one in five of the 600 breached organizations it studied reported a breach due to shadow AI. Organizations with high levels of shadow AI saw breach costs an average of $670,000 higher than those with little or none.

This guide covers how a SOC hunts each of those surfaces with logs it already collects and what normal looks like on each. It also covers how to fold the hunts into a proactive threat hunting program, and it leaves out AI governance policy, model security, and securing the LLM applications you build.

{{ebook-cta}}

What shadow AI detection has to cover

Most shadow AI turns up on six surfaces, and activity on each one lands in a different mix of log sources. AI features built into SaaS you already approved, such as an assistant switched on inside a collaboration tool, are a separate case. They are managed in that vendor's admin settings and fall outside this guide. The table below maps each surface to the telemetry that records it and a first hunt to run.

SurfaceExampleTelemetryFirst hunt
AI chat and SaaS apps in the browserA personal chatbot account used for work, with files uploaded to itProxy, DNS, secure web gateway and CASB logsFirst-seen AI domains per user, and upload volume to AI services
AI apps connected through OAuthA meeting-notes or email assistant granted access to a mailboxEntra ID and Google Workspace audit logs, SaaS admin logsUser consents that grant mail or file access
AI browser extensions and desktop appsAn AI writing extension that can read every pageBrowser management reports, EDR process and file telemetryInstalled AI extensions and apps compared with the approved list
AI coding agents, CLIs, IDE extensions and MCP serversA coding CLI run with its permission prompts turned offEDR process, file and network telemetryAgent processes that read credentials, write persistence or reach new destinations
Local model runtimes and downloaded modelsA local model server running on a workstationEDR process and listening-port data, proxy logs for model downloadsModel runtime processes, exposed ports and large model downloads
AI API calls from servers, scripts and cloud workloadsA service account calling a model provider with a key from a config fileDNS and egress logs, cloud audit logs, secret scanningServers and cloud identities calling model APIs, and AI provider keys in code

Each row can be run as a hypothesis-driven hunt. Write down what unapproved use would look like on that surface, run the search, and keep what you learn about normal so the next run is faster.

How to find AI chat and SaaS use in proxy, DNS and CASB logs

If you already send proxy and DNS logs to your SIEM, they are the cheapest place to detect shadow AI in the browser. Start from a published list of AI services rather than building your own. The Microsoft Defender for Cloud Apps catalog has a Generative AI category with more than a thousand generative AI apps, each with a risk assessment. Microsoft's Global Secure Access adds a shadow AI discovery feature that looks for known generative AI apps, SaaS MCP servers and AI model providers in internet traffic routed through Microsoft Entra Internet Access (part of Entra Suite, or licensed standalone), according to its documentation. If your secure web gateway or CASB keeps its own AI category, use that instead, since its labels already match your logs.

Three hunts cover most of this surface:

  • First-seen AI domains. Flag a user or department reaching an AI-category domain for the first time in 30 days. One visit tells you little. Repeated use by several people on one team is the pattern to review, because it can mean the team adopted a tool that was never approved.
  • Upload volume to AI services. Sum request bytes per user to AI-category destinations and, where the proxy decrypts TLS, count POST requests too, then review the outliers. Uploads are one route company documents take into an AI service, so where uploads already raise DLP alerts, join the two data sets. Sustained, high-volume uploads belong in the same review as other data exfiltration hunts.
  • Personal accounts on sanctioned services. For many services, the domain alone does not tell a company workspace from a personal account. Pair proxy data with the sanctioned service's own audit logs where the vendor provides them, and treat use that appears in the proxy but not in the company tenant as a likely personal account.

Normal on this surface is the company's sanctioned AI tenants and the people licensed for them, and the main limit is coverage. Proxy and DNS logs see only the traffic that crosses them, so personal devices, phones and off-network laptops stay out of view unless an endpoint agent or SSE client carries the traffic. Browsers that use DNS over HTTPS to an outside resolver also skip your DNS logs. Desktop apps and CLIs also call these domains, and a network proxy records that traffic without the process that sent it. Naming the process takes endpoint data: an SSE client such as Microsoft's Global Secure Access client, whose traffic logs carry an InitiatingProcessName field, or the EDR data covered below.

How to find AI apps connected to corporate data

An AI app connected through OAuth usually reads mail and files through an API from the vendor's own servers, so that access does not pass through your proxy. In Microsoft Entra ID, the grant stays in place until someone removes it, and every consent writes an audit event with the activity Consent to application in the Core Directory service. Microsoft's security operations guide separates user consent from admin consent with one property: end-user consent carries ConsentContext.IsAdminConsent set to false.

Run the hunt on user consents, then read each one alongside the permissions it granted. The matching Add delegated permission grant event shows the scopes. Delegated Microsoft Graph permissions such as Mail.Read and Files.Read.All let an app read the user's mail, or every file the user can open in OneDrive and SharePoint. A grant whose DelegatedPermissionGrant.ConsentType is AllPrincipals covers the whole tenant, which requires admin consent. Microsoft's own triage guidance is a fair starting point: consenting to an app is not malicious in itself, so look first at privileged accounts, high-risk permissions, and apps with generic or misspelled names. Entra ID keeps audit logs for seven days on the Free edition and 30 days on P1 and P2, so a hunt that looks back further needs them routed to a SIEM or a storage account, or retained in Microsoft Purview Audit where the license includes it.

Google Workspace records the same kind of event. The Reports API's token activity logs an authorize event each time a user grants an app access, with app_name and scope parameters, and the Admin console shows the same data as OAuth log events. For apps granted access before the hunt began, the Accessed apps list under API controls shows each app that has accessed Google data, with its user count and the scopes it uses. For the SaaS platforms that hold your source code, tickets and customer data, add each one's admin log of third-party app installs to the same hunt where the platform keeps one.

Normal is the set of apps an admin has approved, and for shadow AI detection on this surface the lead is any AI app outside that set holding mail or file access. The Microsoft Graph activity logs show what such an app did with that access, recording its Graph API requests by AppId. They need Entra ID P1 or P2 and collection turned on in diagnostic settings. Tenants that already block user consent will see few user-consent events. Microsoft's managed consent setting, the default for new tenants, also stops users from consenting to scopes such as Mail.Read and Files.Read.All. In those tenants the same review runs over admin approvals instead. Consents older than your retained audit logs will not appear in the hunt, so take the starting inventory from each enterprise app's Permissions page or, for delegated grants, Microsoft Graph's oauth2PermissionGrants.

How to hunt AI agents and coding CLIs on endpoints

Endpoints are the part of shadow AI detection where the stakes often run highest, because coding agents run shell commands, read files and use the developer's own credentials as part of normal work. EDR process, file and network telemetry is the main data source for AI agent monitoring on those machines, alongside whatever logs the agents keep themselves. The hunt runs in two passes: an inventory of what is installed, then a search for behavior that falls outside a developer's normal work.

Start with an inventory

An inventory answers the first question a new tool incident raises: which hosts have this tool, and at which version. Build it from four kinds of data:

  • Agent and CLI processes. Coding CLIs such as claude, codex, gemini, q and its renamed successor kiro-cli, and desktop apps such as Cursor and the Claude and ChatGPT desktop apps. Some of these CLIs run as node processes, so match on the command line as well as the image name.
  • IDE extensions. Publisher, extension ID and version, read from extension folders such as ~/.vscode/extensions, or wherever VS Code's --extensions-dir option or VSCODE_EXTENSIONS variable points.
  • Browser extensions. Browser management consoles and many EDR products can list installed extensions with their permissions. An AI extension allowed to read every page can see what the user sees, internal apps included.
  • MCP servers. Local MCP servers are binaries downloaded and run on the same machine as the agent, as the MCP security guidance puts it. Their configuration sits in files such as .mcp.json and ~/.claude.json for Claude Code, and .cursor/mcp.json and ~/.cursor/mcp.json for Cursor.

Local model runtimes belong in the same inventory. Ollama, for example, listens on 127.0.0.1 port 11434 by default and stores models under ~/.ollama/models on macOS, per its FAQ. A runtime rebound to a non-loopback address through OLLAMA_HOST can expose its API to the rest of the network, which is worth a separate alert. Large model-file downloads from model hubs also appear in proxy logs.

Then hunt the behavior

Coding agents run shell commands as part of ordinary development work, so hunting for shell use alone returns mostly normal activity. The hunts below target what everyday agent use rarely needs: permission prompts turned off by a script, encoded or policy-bypassing shells, credential reads outside the project, new persistence, and new destinations.

Permission prompts turned off. Claude Code, Gemini CLI and Kiro CLI (formerly Amazon Q Developer CLI) check commands before running them by default, with a user prompt or, in Claude Code's auto mode, a classifier. Each has a flag that turns those checks off: --dangerously-skip-permissions, --yolo and --trust-all-tools, in that order. In the August 2025 Nx compromise, malicious npm packages ran whichever of these CLIs they found. They passed each CLI a prompt that told the agent to write the paths of credential and wallet files to /tmp/inventory.txt, according to StepSecurity and Snyk. The packages then published what they collected to a public GitHub repository whose name contained s1ngularity-repository, using the victim's own token, and appended sudo shutdown -h 0 to ~/.bashrc and ~/.zshrc. The Mastra npm compromise also delivered its payload through an install-time loader. Hunt for these flags where the parent process is a package manager or an install script rather than an interactive terminal. Include other flags that turn off approval checks, such as --permission-mode bypassPermissions in Claude Code, --approval-mode=yolo in Gemini CLI and --dangerously-bypass-approvals-and-sandbox in Codex CLI. CI jobs and sandboxed containers sometimes use the same flags on purpose, so check the parent process and the host before treating a hit as suspicious. Settings files can also pre-approve commands, so a missing flag does not prove the prompts were on.

Encoded or policy-bypassing shells. An agent or IDE extension host that starts PowerShell with -EncodedCommand or -ExecutionPolicy Bypass, including short forms such as -ec and -ep, deserves a look, as does any shell that downloads and runs a script in one line. On Windows, the PowerShell extension for VS Code starts its language server with -ExecutionPolicy Bypass by default, so baseline extensions that do this before alerting. Agents often write and run scripts, so scope this hunt to the agent's process tree and compare against what that developer's agents usually run.

Credential reads outside the project. Agents read project files, including .env files, as part of normal work. Reads of SSH private keys under ~/.ssh/, cloud credential files such as ~/.aws/credentials, or browser credential stores fall outside most coding tasks. So does a call to gh auth token, which is how the Nx malware collected GitHub tokens. A cloud CLI that the agent runs will read its own credential file, though, and ssh can read the user's private key when the agent pushes to an SSH remote with git. The stronger signals are the agent process, or a script it wrote, reading the file directly, and a credential read followed by a connection to an unfamiliar destination. Include the process that launched the agent, too: in the Nx case, the agent was told only to list file paths, and the install script that started it read the files. This hunt needs file-read telemetry, which not every sensor records (Sysmon, for example, has no file-read event), so confirm your EDR captures reads of these paths before trusting a quiet result.

Persistence created by an agent or extension. Look for writes to ~/.ssh/authorized_keys (on Windows, also %programdata%\ssh\administrators_authorized_keys, which OpenSSH reads for administrator accounts), new LaunchAgents, cron entries, scheduled tasks, Startup-folder scripts and shell profile changes where the writing process descends from an agent CLI or an IDE extension host. These map to ATT&CK techniques such as SSH Authorized Keys (T1098.004), Launch Agent (T1543.001) and Scheduled Task (T1053.005). Developers do sometimes ask an agent to set up a cron job or edit a shell profile, and installers such as the nvm install script edit profiles too, so expect legitimate hits to review. An attacker can also persist through the agent's own configuration. A startup command added to an MCP configuration file, or a hook added to Claude Code's settings files, can run every time the agent starts, so include changes to those files.

Destinations beyond the AI provider. Agent processes and their children routinely connect to the model provider, package registries and code hosts. Outbound SSH to anything other than your code hosts and each developer's usual servers, connections to raw IP addresses, and new domains outside that set are the cases to review. Agents with a web-fetch tool, such as Claude Code's WebFetch, also pull pages from arbitrary sites during ordinary tasks, so weigh a new domain against what the agent did before and after it. A destination inside that set proves little by itself, though, because the Nx packages sent what they collected to GitHub; the parent-process and credential-read hunts above are better placed for that case. When one of these hunts trips an existing EDR rule, the usual steps for investigating EDR alerts apply to the agent's process tree.

Worked example: the October 29 extension

The tampered Claude Code extension trips the persistence and destination hunts above: a write to authorized_keys, new persistence, and outbound SSH to a raw IP address. StepSecurity found that loading the extension was enough to run its loader, which collected host details and the names of environment variables and posted them to the attacker over plain HTTP. Indicators published by Cursor and StepSecurity include:

  • Extension folders named anthropic.claude-code-2.1.312-* or anthropic.claude-code-2.1.313-* whose extension.js contains svc-telemetry
  • An authorized_keys entry, or on Windows an entry in %programdata%\ssh\administrators_authorized_keys, with the key comment svc-telemetry
  • Connections to 134[.]209[.]82[.]225 on TCP 22, and HTTP POST requests to port 8099 at /beacon
  • The command lines ssh -N -R '*:0:localhost:22' and autossh -M 0
  • A macOS LaunchAgent at ~/Library/LaunchAgents/com.apple.sysmond.plist
  • A Windows scheduled task named SysMon, with a fallback script at %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\sysmon.cmd
  • Persistence scripts at ~/.config/.smt and ~/.config/.smtk

Two cautions from the responders carry over to other extension incidents. Having one of these versions installed does not by itself mean a host is compromised, StepSecurity noted. Check first whether the host downloaded or updated the extension from Cursor's marketplace between about 09:27 and 20:35 UTC on October 29, then look for the indicators above. Uninstalling the extension also does not remove the persistence scripts, which keep running on their own, according to Cursor. Cursor tells customers to isolate hosts that show evidence of payload execution or backdoor installation, and to remove the attacker's SSH key, the persistence and the running tunnel processes. It also says to rotate, from a trusted system, the credentials and sessions the host could reach, because collecting only variable names does not rule out later credential access over the backdoor. The July 2025 Amazon Q Developer case shows the same need for version-level inventory. AWS found malicious code in version 1.84.0 of its VS Code extension that failed to run because of a syntax error. In bulletin AWS-2025-015, it told customers to remove every 1.84.0 installation and move to 1.85.0. With an inventory in place before the advisory lands, the first question in emerging threat response takes one query: which hosts have the affected version.

How to tell when an agent session was prompt-injected

The prompt injection a SOC hunts for in agent sessions is the indirect kind. An attacker plants instructions in content the agent reads during a task, such as a web page, an issue, a README or a tool result. OWASP lists prompt injection as LLM01:2025 and describes the indirect form as input from external sources, such as websites or files, that alters the model's behavior when interpreted. MITRE ATLAS tracks it as AML.T0051, with indirect injection as AML.T0051.001.

From the SOC's side, the sequence to look for has three steps. First, the agent reads outside content, whether fetched mid-session or already in the workspace, such as a cloned repository's README. Next, a new instruction appears in that content. Then the agent takes an action outside the user's task, such as reading credentials, sending data to a new destination or installing something. Confirming it usually takes two kinds of data: one to show where the instruction came from, and one to show what the agent did.

  • Agent transcripts. Some tools keep full session logs on disk. Claude Code writes each session's messages, tool calls and tool results as JSONL files under ~/.claude/projects/. It keeps them for 30 days by default and does not encrypt them at rest, according to its documentation. Setting CLAUDE_CONFIG_DIR moves them, and setting CLAUDE_CODE_SKIP_PROMPT_HISTORY, or passing --no-session-persistence with -p, stops them from being written. Any credential the agent read or printed is written into them in plain text, so a transcript also shows which secrets to rotate. Other tools vary, so check what each tool you allow keeps.
  • LLM gateway logs. Azure API Management can send prompts and completions to the ApiManagementGatewayLlmLog table once a diagnostic setting sends the generative AI gateway logs to a Log Analytics workspace and logging of LLM messages is enabled for the API, per Microsoft's documentation.
  • Model invocation logs. Amazon Bedrock's model invocation logging records prompts and responses, but it is off by default and covers only calls made through the bedrock-runtime endpoint, per AWS documentation.
  • Endpoint and cloud telemetry. The action half of the sequence lands in EDR and cloud audit logs. An action taken through an MCP server may be recorded only by the connected service. Invariant Labs' GitHub MCP research showed an injected agent leaking private repository data through a pull request it opened in a public repository.

Join the timestamp of the fetch or file read in the transcript to the agent's process tree in EDR, and look at what the agent did after it, through the end of the session. For tool calls made through an MCP server, check the connected service's audit log for the same window, where the service keeps one. Suspicious text in a transcript with no matching action stays a lead until the endpoint or cloud data shows the agent acted on it.

How to find AI API use from servers, scripts and cloud workloads

Model API calls from servers and scripts run without a browser or a user at a keyboard, so they need their own hunt. Three data sources cover most of it.

Egress from servers and service accounts. Look for servers, containers and service accounts resolving or connecting to model provider APIs such as api.openai.com, api.anthropic.com and generativelanguage.googleapis.com, and to Azure OpenAI endpoints under openai.azure.com. DNS resolver logs record the hostnames workloads look up, where resolver logging is on. In AWS, Route 53 Resolver query logging covers only the VPCs you specify and skips queries answered from its cache. A workload can therefore reach a model API without a log line of its own. Flow logs carry only IP addresses, and an IP address rarely identifies the service behind it.

Cloud audit logs. CloudTrail records the Bedrock runtime calls InvokeModel, InvokeModelWithResponseStream, Converse and ConverseStream as management events, which CloudTrail logs by default, according to AWS. Each event names the calling principal and the modelId but does not include the prompt text, so the hunt looks for a principal or model seen for the first time. Inference through the bedrock-mantle endpoint (logged as CreateInference), the bedrock-runtime calls StartAsyncInvoke and InvokeModelWithBidirectionalStream, and Bedrock Agents calls such as InvokeAgent are data events, which CloudTrail does not log by default. A first-time caller can also be an attacker using stolen credentials, a pattern Sysdig reported as LLMjacking, so compare the calls' sourceIPAddress and userAgent with the principal's earlier activity. Where invocation logging is in use, a DeleteModelInvocationLoggingConfiguration call deserves an alert, as does a PutModelInvocationLoggingConfiguration call that turns off text delivery or sends the logs somewhere new. In Azure, the Activity Log records new Azure OpenAI resources, along with Foundry Tools (formerly Azure AI services), under the Microsoft.CognitiveServices/accounts/write operation. Resources created outside the subscriptions approved for AI are the lead to follow. New model deployments inside approved resources are logged as Microsoft.CognitiveServices/accounts/deployments/write.

AI provider keys. Secret scanning across repositories, CI logs and wikis finds keys that tie code to a provider. GitHub's secret scanning, for example, detects Anthropic API keys, though on organization-owned private and internal repositories it requires GitHub Secret Protection. Compare what you find with the keys issued from the company's own provider accounts. A working key that belongs to no company account points to a personal or team account handling company data.

Normal on this surface is a short list of approved applications, each with a named owner, a provider and the models it uses. Anything that calls a model API and is missing from that list goes to its owner for review, or, if it has none, gets turned off once you know what depends on it.

How to run shadow AI detection as a standing hunt

A one-time inventory goes stale the first time a developer installs a new tool or an extension updates itself. Running shadow AI detection on a schedule keeps the inventory current, and the behavioral hunts become candidates for detection engineering once their false positives are tuned out. A reasonable starting cadence:

  • Browser and SaaS use: a weekly review of first-seen AI domains and upload outliers.
  • Connected apps: an alert on user or admin consents that grant mail or file access, plus a weekly review of all new grants.
  • Endpoint inventory: a weekly diff of AI tools, extensions with their versions, MCP configurations and local model runtimes.
  • Endpoint behavior: daily runs of the permission-flag, encoded-shell, credential-read, persistence and destination hunts, moved into detection rules once tuned.
  • Servers and cloud: a weekly review of principals calling model APIs, plus an alert on changes to model logging configuration.

Each finding goes one of three ways. A tool that is useful and low-risk gets sanctioned and moves to the approved list with an owner. A tool the company will not allow gets blocked at the proxy, revoked in the identity provider or removed from endpoints, with a control that keeps it from coming back. In Entra ID, revoking an app's grant does not stop users from consenting to it again, so disable sign-in for the app as well. In VS Code, the AllowedExtensions policy also disables blocked extensions that are already installed. Anything involving credential access, persistence or an unknown destination, if a review cannot explain it, goes to incident response as a possible compromise. That includes rotating the credentials the agent could reach and ending the sessions already issued with them. AWS temporary credentials, for example, stay valid until they expire, so revoke their permissions too, then watch for any further use of the old credentials to confirm the rotation held.

Running a dozen standing hunts, and investigating what they return, takes analyst hours that usually go to the alert queue first. AI threat hunting agents can run the scheduled part of that work and bring the leads that need a person back to the team. Prophet AI Threat Hunter's Custom Hunting Agents turn plain-language questions like the ones in this guide into standing hunts on the schedule your team sets. Suspicious leads go to the Prophet AI SOC Analyst for a full investigation.

Table of contents
Add as Google Preferred Sources

Insights

Prophet Security Quarterly Threat Report

The attack patterns seen most across customer environments, and why some of those attacks succeeded where others were blocked.

Download Report
Ajmal Kohgadai

Ajmal Kohgadai

As the Director of Product Marketing at Prophet Security, Ajmal drives marketing and growth strategies and helps security professionals see how AI is transforming security operations.