Detection rules › Kusto

Copilot - File Uploads Disabled

Status
available
Severity
high
Time window
1h
Source
github.com/Azure/Azure-Sentinel

'Detects when file uploads are disabled in Copilot. Attackers often disable logging or file upload capabilities to avoid evidence collection and cover their tracks. This rule identifies potential data exfiltration cover-up scenarios where security controls are being disabled.'

MITRE ATT&CK coverage

Rule body kusto

id: c3d4e5f6-a7b8-49c0-d1e2-f3a4b5c6d7e8
name: Copilot - File Uploads Disabled
description: |
  'Detects when file uploads are disabled in Copilot. Attackers often disable logging or file upload capabilities to avoid evidence collection and cover their tracks.
  This rule identifies potential data exfiltration cover-up scenarios where security controls are being disabled.'
severity: High
status: Available
requiredDataConnectors:
  - connectorId: MicrosoftCopilot
    dataTypes:
      - CopilotActivity
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - DefenseEvasion
relevantTechniques:
  - T1562.001
query: |
  CopilotActivity
  | where RecordType == "DisableCopilotPlugin"
  | extend Resource = parse_json(LLMEventData).Resource[0]
  | extend Property = tostring(Resource.Property)
  | extend Old = tostring(Resource.OriginalValue)
  | extend New = tostring(Resource.NewValue)
  | where Property == "FileUploads" and Old == "Enabled" and New == "Disabled"
  | project TimeGenerated, ActorName, SrcIpAddr, Property, Old, New
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: ActorName
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: SrcIpAddr
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

CopilotActivity

Stage 2: where

| where RecordType == "DisableCopilotPlugin"

Stage 3: extend (4 consecutive steps)

| extend Resource = parse_json(LLMEventData).Resource[0]
| extend Property = tostring(Resource.Property)
| extend Old = tostring(Resource.OriginalValue)
| extend New = tostring(Resource.NewValue)

Stage 4: where

| where Property == "FileUploads" and Old == "Enabled" and New == "Disabled"

Stage 5: project

| project TimeGenerated, ActorName, SrcIpAddr, Property, Old, New

Indicators

Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.

FieldKindValues
Neweq
  • Disabled transforms: cased
Oldeq
  • Enabled transforms: cased
Propertyeq
  • FileUploads transforms: cased
RecordTypeeq
  • DisableCopilotPlugin transforms: cased

Output fields

Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.

FieldSource
ActorNameproject
Newproject
Oldproject
Propertyproject
SrcIpAddrproject
TimeGeneratedproject