elastic / elastic/integrations
[M365] Add Microsoft 365 Copilot activity log support
- Dominant language
- Handlebars
- Stars
- 333
- Forks
- 647
- Avg merge
- 2d 18h
- Merged PRs (30d)
- 182
Description
# Description
Microsoft 365 Copilot is the highest-penetration enterprise AI tool by seat count. Copilot interactions — who used Copilot, where they used it, and which documents it read to build the answer — are auditable via the Office 365 Management Activity API, and they already arrive through the `Audit.General` content type that the existing `o365` integration collects by default.
**No new API, credential, or permission is required.** The gap is entirely in the ingest pipeline: the `RecordType` lookup map doesn't recognise the Copilot record types, and the Copilot payload (which is nested under a `CopilotEventData` object) has no field mappings. Copilot events land today with only generic handling applied, so the fields that matter for security use cases are unmapped.
This is an enhancement to the existing `o365` `audit` data stream, not a new data stream.
## What this data does (and doesn't) give you
Unlike most AI-usage telemetry, Copilot audit events are unusually rich — most of the work is mapping fields that are already in the payload.
**What `CopilotInteraction` events expose** (Copilot-specific fields sit under `CopilotEventData`):
- **The resources Copilot grounded its answer on** — `AccessedResources[]` gives document ID, `Name`, `SiteUrl`, `Type`, the `Action` taken, and the **`SensitivityLabelId`** (Purview label) of each resource. This is the standout signal: you can see *which sensitive documents* an AI response was built from.
- **Where the interaction happened** — `AppHost` (Word, Teams, Outlook, BizChat, Excel, SharePoint, …) and `AppIdentity` (`workloadName.appGroup.appName`), which identifies the specific Copilot or AI app.
- **Built-in safety signals** — `XPIADetected` (cross-prompt-injection attempt flagged on a resource) and `JailbreakDetected` (flagged on a prompt message). These are genuine threat signals, not just governance metadata.
- **Model transparency** — `ModelProviderName`, plus `ModelName`/`ModelVersion` in some non-M365 scenarios.
- **Conversation structure** — `Messages[]` (message ID and prompt-vs-response flag) and `ThreadId`, which lets related interactions be stitched together.
- **Web grounding** — `AISystemPlugin` containing `BingWebSearch` indicates the response used the public web.
**What it does not expose:**
- **The text of prompts and responses.** `Messages[]` carries identifiers only (`Id`, `isPrompt`, `Size`) — there is no content field in the audit schema at *any* licence tier. Audit (Premium) adds retention and API bandwidth, not content. Retrieving actual prompt/response text requires a different API entirely: Microsoft Graph [`aiInteractionHistory`](https://learn.microsoft.com/en-us/graph/api/aiinteractionhistory-getallenterpriseinteractions?view=graph-rest-beta) (`AiEnterpriseInteraction.Read.All`, application permission, currently beta) or eDiscovery. That endpoint is queried per-user, so an integration would need to enumerate licensed users and fan out — a separate data stream and a separate design discussion. **Out of scope for this issue.**
- **Human-readable sensitivity label names.** `SensitivityLabelId` is a GUID. Resolving it to a label name needs the tenant's label taxonomy from Microsoft Graph (`informationProtection/sensitivityLabels`) — a possible enrichment, but not available from the event itself. See open questions below.
The practical consequence: this is a strong **visibility and correlation** signal at the standard audit tier. Elastic can surface which sensitive documents Copilot touched, in which app, by which user, and whether injection or jailbreak attempts were flagged — without any premium licensing.
## Scope & data boundaries
- **Enhancement, not a new data stream:** record-type handling plus field mapping in the existing `o365` `audit` pipeline. Copilot events already arrive via `Audit.General`.
- **No new access required:** same Management Activity API, same Entra app registration, same permission the integration already uses.
- **Prompt/response content is out of scope** — it isn't in these events (see above).
- **Correlation** with other M365 signals (anomalous sign-in, bulk SharePoint access, privileged-account activity) works **today** against the existing `o365` data streams — no additional collection required.
- **Sensitivity-label resolution** (GUID → label name) is an open question to settle during development, not a committed deliverable.
## Why this matters
- **Sensitive-data visibility:** `AccessedResources[].SensitivityLabelId` shows when Copilot grounded a response in labelled, sensitive material. Correlating that with the user, app surface, and surrounding M365 activity is the primary security signal in these events.
- **Threat detection:** Copilot activity joined with other M365 signals already in Elastic produces higher-fidelity detections than either source alone — plus the native `XPIADetected` / `JailbreakDetected` flags.
- **AI governance:** Track which users, departments, and app surfaces are using Copilot, and surface anomalous usage patterns.
- **Compliance & audit:** A durable, queryable record of AI tool usage to support GDPR, HIPAA, and internal acceptable-use requirements.
- **Admin oversight:** Copilot admin operations (tenant setting changes, plugin add/remove, promptbook changes) are configuration changes that should be monitored like any other.
## What needs to be supported
**Record types.** Verified against the [Management Activity API schema](https://learn.microsoft.com/en-us/office/office-365-management-api/office-365-management-activity-api-schema#auditlogrecordtype):
| RecordType | Value | Covers |
|---|---|---|
| `CopilotInteraction` | 261 | Microsoft-developed Copilot apps — M365 Copilot, Security Copilot, Copilot Studio apps. **Primary target.** |
| `TeamCopilotInteraction` | 334 | Teams Facilitator — AI Notes, Live Notes, meeting moderation |
| `ConnectedAIAppInteraction` | 328 | Third-party AI apps deployed and registered in the tenant |
| `AIAppInteraction` | 284 | Third-party AI apps not deployed in the tenant |
Copilot admin activity is logged both under dedicated admin record types (the 310–325 range, plus 363 `Microsoft365CopilotScheduledPrompt`) and via `Operation` names such as `UpdateTenantSettings`, `CreatePlugin`, `DeletePlugin`, and `EnablePromptBook`.
> **Note on availability:** 261 and 334 are covered by Audit (Standard). 284 and some 328 records are **pay-as-you-go billed** and only appear if the tenant has Purview pay-as-you-go enabled with an attached Azure subscription. Build and test against 261 first; treat 284/328 as follow-on.
**Key fields to map:**
| Field | Description |
|---|---|
| `UserId` | The user who interacted with Copilot |
| `Operation` / `RecordType` | `CopilotInteraction` — the AI interaction event |
| `CopilotEventData.AppHost` | Copilot surface (`Word`, `Teams`, `Outlook`, `BizChat`, `Excel`, `SharePoint`, …) |
| `AppIdentity` | Specific Copilot/AI app (`workloadName.appGroup.appName`) |
| `CopilotEventData.AccessedResources[]` | The grounding documents Copilot read — `Id`, `Name`, `SiteUrl`, `Type`, `Action` |
| `CopilotEventData.AccessedResources[].SensitivityLabelId` | Purview sensitivity label (GUID) on the grounding doc — primary DLP signal |
| `CopilotEventData.AccessedResources[].XPIADetected` | Cross-prompt-injection attack flagged on a resource |
| `CopilotEventData.AccessedResources[].PolicyDetails` / `.Status` | Present when Copilot's access to a resource was blocked or restricted by policy |
| `CopilotEventData.Messages[].isPrompt` / `.JailbreakDetected` | Prompt vs. response; jailbreak-attempt flag |
| `CopilotEventData.ThreadId` | Conversation thread identifier, for stitching interactions together |
| `CopilotEventData.ModelTransparencyDetails[].ModelProviderName` | Model publisher |
| `CopilotEventData.AISystemPlugin[].Id` | `BingWebSearch` indicates the response used the public web |
| `ClientRegion` | User's region at the time of the interaction |
**Dashboards:** Copilot usage by user and app surface, sensitivity-label exposure in grounding contexts, admin configuration-change timeline, usage volume over time.
## Sample event
Shape taken from the [documented `CopilotInteraction` schema](https://learn.microsoft.com/en-us/office/office-365-management-api/copilot-schema); note that the Copilot-specific fields are **nested under `CopilotEventData`**, and use `Id` rather than `ID`. A real captured event should be added during development.
```json
{
"CreationTime": "2026-06-01T14:23:11",
"Id": "aaaa1111-bbbb-2222-cccc-3333dddd4444",
"Operation": "CopilotInteraction",
"OrganizationId": "11112222-3333-4444-5555-666677778888",
"RecordType": 261,
"UserKey": "12d24f71-64c7-49b3-821f-f8884f3f373e",
"UserId": "analyst@contoso.com",
"UserType": 0,
"Version": 1,
"Workload": "Copilot",
"ClientIP": "2401:4900:60d2:179b:c004:b6f:b678:b148",
"ClientRegion": "US",
"AppIdentity": "Copilot.MicrosoftCopilot.BizChat",
"CopilotEventData": {
"AppHost": "Word",
"ThreadId": "19:Xn3uQZYgZ7f2ue0vp5w9MglEVjFyp5pza1efaC6g2U41@thread.v2",
"Contexts": [
{
"Id": "https://contoso.sharepoint.com/sites/Finance/Shared Documents/Q3-Forecast.docx",
"Type": "docx"
}
],
"AccessedResources": [
{
"Action": "Read",
"Id": "AAAAAEYE2GAACp1FlnN_CHXStUkH...AABwvq8gAAA2",
"Name": "Q3-Forecast.docx",
"Type": "docx",
"SiteUrl": "https://contoso.sharepoint.com/sites/Finance/Shared Documents/Q3-Forecast.docx",
"listItemUniqueId": "AAAAAEYE2GAACp1FlnN_CHXStUkH...AABwvq8gAAA2",
"SensitivityLabelId": "f41ab342-8706-4188-bd11-ebb85995028c",
"XPIADetected": false
}
],
"Messages": [
{ "Id": "1715186983849", "isPrompt": true, "JailbreakDetected": false },
{ "Id": "1715186984291", "isPrompt": false }
],
"MessageIds": [],
"ModelTransparencyDetails": [
{ "ModelProviderName": "Microsoft" }
],
"AISystemPlugin": [
{ "Id": "BingWebSearch", "Name": "BuiltIn" }
]
}
}
```
## Access requirements
**Collection — nothing new needed.** Copilot events use the same Office 365 Management Activity API, the same Entra app registration, and the same `ActivityFeed.Read` application permission (with admin consent) that the `o365` integration already requires. `Audit.General` is already in the integration's default `content_types`, and Copilot auditing is enabled automatically once unified audit logging is on for the tenant — there is nothing extra for a user to configure.
**For development and testing:** a tenant with unified audit logging enabled **and at least one assigned Microsoft 365 Copilot seat** (a paid per-user add-on). Without a Copilot seat, no `CopilotInteraction` records are generated — an E5 tenant on its own provides the audit plumbing but no events. This licensing requirement, not API access, is the practical prerequisite for capturing real sample data. Pipeline test fixtures can be built from the documented sample records in the meantime, so most of the work can start before a licensed tenant is available.
**Licence tiers:**
- **Audit (Standard)** (M365 E3/E5): captures the events with full metadata, including sensitivity label IDs on grounding documents.
- **Audit (Premium)** (E5 or add-on): adds extended retention (up to 10 years) and higher API bandwidth. It does **not** add prompt/response content.
## Implementation notes
1. Add the Copilot record types (261, 284, 328, 334, plus the admin record types) to the `RecordType` map in the `audit` ingest pipeline — it currently stops at 181.
2. Add a `CopilotEventData` field group to the `audit` data stream's `fields.yml`, matching the nested structure above.
3. Apply ECS categorisation for interaction events and admin configuration changes, and promote `XPIADetected` / `JailbreakDetected` to fields that detection rules can query directly.
4. Add pipeline test fixtures and a real captured sample event.
5. Add dashboards as described above.
**Open question:** how to resolve `SensitivityLabelId` GUIDs to label names. Options include an enrich policy fed from Graph, a dashboard-time lookup, or leaving it to the user. Needs a decision during development — it can't be done from the event alone.
## References
- [Audit logs for Copilot and AI applications — Microsoft Purview](https://learn.microsoft.com/en-us/purview/audit-copilot)
- [`CopilotInteraction` schema — Office 365 Management Activity API](https://learn.microsoft.com/en-us/office/office-365-management-api/copilot-schema)
- [Management Activity API — RecordType values](https://learn.microsoft.com/en-us/office/office-365-management-api/office-365-management-activity-api-schema#auditlogrecordtype)
- [Microsoft Purview data security for Copilot](https://learn.microsoft.com/en-us/purview/ai-microsoft-purview)
- [Existing o365 ingest pipeline](https://github.com/elastic/integrations/blob/main/packages/o365/data_stream/audit/elasticsearch/ingest_pipeline/default.yml)
Contributor guide
Assessment
This issue has not been assessed yet.