KQL queries, Intune remediation scripts, and documentation for discovering local AI agent infrastructure on managed endpoints.
Detects what Microsoft tools don't — yet: vector databases, agent memory files, Docker containers, local LLM runtimes, and API key storage that AI coding agents leave on developer workstations.
Built for Microsoft Defender XDR, Microsoft Sentinel, and Intune.
| # | Query | Severity | Table |
|---|---|---|---|
| 01 | ChromaDB vector databases | Medium | DeviceFileEvents |
| 02 | FAISS vector index files | Medium | DeviceFileEvents |
| 03 | AI agent memory & config files | Low-Medium | DeviceFileEvents |
| 04 | Local LLM processes (Ollama, vLLM, llama.cpp) | Medium | DeviceProcessEvents |
| 05 | Docker containers with AI workloads | Medium-High | DeviceProcessEvents |
| 06 | Local LLM API port listeners | Low-Medium | DeviceNetworkEvents |
| 07 | .env files with LLM API keys | High | DeviceFileEvents |
| 08 | Shadow AI network traffic baseline | Informational | DeviceNetworkEvents |
Plus: Intune Proactive Remediation script for fleet-wide scanning.
- Open Microsoft Defender XDR → Hunting → Advanced hunting
- Paste this query and click Run query:
DeviceNetworkEvents
| where Timestamp > ago(24h)
| where RemoteUrl has_any ("openai.com","anthropic.com","claude.ai",
"huggingface.co","api.deepseek.com","cursor.sh")
| summarize Connections = count()
by DeviceName, InitiatingProcessAccountName, RemoteUrl
| order by Connections descYou'll see every device talking to AI APIs.
- Open Intune Admin Center → Devices → Scripts and remediations
- Upload
Detect-ShadowAI.ps1 - Configure: Run as System · 64-bit PowerShell · Daily schedule
- Assign to your managed device groups
Defender for Endpoint, Agent 365, Intune
What local AI tooling leaves on disk — the exact paths and files targeted by the detections above.
chroma_data/
├── chroma.sqlite3 ← SQLite: metadata, WAL, embeddings
└── {UUID}/
├── data_level0.bin ← HNSW vectors (float32)
├── header.bin
├── length.bin
└── link_lists.bin
Port 8000 (server mode) · Detection: chroma.sqlite3 + UUID sibling dirs
faiss_store/
├── index.faiss ← Binary index (IVF/HNSW/Flat)
├── index.pkl ← Docstore ID mapping
└── *.npy (optional)
No network component · Detection: *.faiss files near vector-related paths
~/.ollama/
├── models/manifests/registry.ollama.ai/library/{model}/
└── blobs/sha256-{hash} ← Model weights (multi-GB GGUF)
Port 11434 · Process ollama / ollama.exe · Docker: ollama/ollama
~/.cache/huggingface/hub/
└── models--{org}--{model}/
├── config.json
├── model-*.safetensors
└── tokenizer.json
Port 8000 · Process: vllm.entrypoints · Docker: vllm/vllm-openai
project/
├── CLAUDE.md ← Layer 1: human instructions
├── CLAUDE.local.md ← Layer 1: local-only (gitignored)
├── MEMORY.md ← Layer 2: auto-memory (Claude writes)
└── memories/ ← Layer 3: Memory Tool
~/.claude/
├── CLAUDE.md ← User-level instructions
└── agent-memory/{project}/ ← Layer 4: subagent memory
project/
├── .cursorrules ← Legacy single-file rules
└── .cursor/rules/
├── backend.mdc
├── frontend.mdc
└── testing.mdc
project/
├── .aider.conf.yml
├── .aider.chat.history.md ← Full conversation log
├── .aider.input.history
└── .env ← API keys in plaintext
~/.aider.conf.yml ← User-level config
.github/
├── copilot-instructions.md
└── agents/
├── reviewer.agent.md
└── security.agent.md
Port 3113 · ~/.agentmemory/memories.db · Shared by Claude Code, Cursor, Codex, Gemini CLI
~/.cache/huggingface/
├── hub/{model-dirs} ← Downloaded weights (5 GB – 200 GB+)
└── token ← HuggingFace API token (plaintext!)
These configuration states progressively remove human approval from the loop. Security teams should monitor the config files and process flags below.
| Tool | Maximum Autonomy Config | Key Risk |
|---|---|---|
| Cursor | Auto-run terminal commands + Allow file deletion | Shell commands execute without prompting |
| Claude Code | --dangerously-skip-permissions |
Disables ALL permission checks |
| Aider | --auto-commits --yes-always --auto-lint --auto-test |
Commits every edit, accepts all prompts |
| Windsurf | Cascade Flow Mode (default) | Full autonomy is on by default — no opt-in |
| VS Code Copilot | chat.tools.autoApprove: true |
Repo .vscode/settings.json can activate on workspace trust |
| GitHub Copilot | --autopilot CLI flag |
Approval-free issue → code → PR loop |
Defender detection: Local AI Agent Discovery surfaces auto-approve status per agent.
┌──────────────────────────────────────────────────────┐
│ AGENT 365 — Control Plane │
│ Registry · Access Control · Shadow AI · Policy │
└──────────────────┬───────────────────────────────────┘
│
┌──────────────────┼───────────────────┐
│ DEFENDER │ ENTRA ID │ INTUNE │
│ Agent discovery │ Agent IDs │ Policy enforcement │
│ Runtime protect │ Conditional access│ App blocking │
│ Threat detection │ Zero Trust │ Remediation scripts │
└──────────────────┼───────────────────┘
│
┌──────────────────┴───────────────────────────────────┐
│ PURVIEW DSPM for AI │
│ DLP · Sensitivity Labels · Audit · Insider Risk │
└──────────────────────────────────────────────────────┘
│
┌──────────┐ ┌────┴──────────────┐ ┌──────────────────┐
│ MXC │ │ Win 365 for Agents│ │ GitHub Enterprise│
│ Kernel │ │ Managed Cloud PC │ │ AI Controls (GA) │
│ sandbox │ │ Isolated runtime │ │ Model allowlists │
└──────────┘ └───────────────────┘ └──────────────────┘
shadow-ai-hunting/
├── src/ # Astro documentation site
│ ├── components/ # Nav, Footer
│ ├── data/detections.ts # Detection metadata
│ ├── layouts/Layout.astro
│ ├── lib/config.ts
│ ├── pages/index.astro
│ └── styles/
├── public/favicon.svg
├── detections/
│ ├── kql/ # 8 KQL detection queries
│ └── intune/Detect-ShadowAI.ps1
├── astro.config.mjs
├── package.json
├── tsconfig.json
└── LICENSE
- Fork the repo
- Add a new KQL file in
detections/kql/following the numbered naming convention - Use the standard comment header from any existing
.kqlfile - Test against real Defender Advanced Hunting where possible
- Update the detection table above and in
src/data/detections.ts - Submit a PR
MIT — see LICENSE.