Skip to content
Ops Log
Operator RunbookSecurity & Infrastructure28 July 202614 min read

An incident-response playbook for a team without a security operations centre

A first-hours runbook for a 4 to 15 person technical team on Microsoft 365: the three EU reporting clocks and the event that actually starts each one, a containment sequence that captures evidence before it cuts access, and the documented side effects and rollback for every high-blast-radius action.

MJ
Michal Jatczak
Founder, ITSailor

Three EU regimes put a clock on a security incident, and none of them requires a security operations centre. They require a named decision maker, evidence that survives the response, and a filing made against the correct starting event. This runbook covers the first hours for a technical team of roughly 4 to 15 people on Microsoft 365: what has to exist before the alert, the order in which containment actions are safe to run, and the documented reversal for each one.

The three clocks and what starts each one

A countdown anchored to detection misreads the DORA clock. GDPR Article 33 and NIS2 Article 23 both run from awareness of the incident. The DORA initial notification runs from the moment the incident is classified as major, with an outer cap of 24 hours from awareness.

RegimeStageDeadlineMeasured from
GDPR Article 33Notification to the supervisory authority72 hoursBecoming aware of the personal data breach
NIS2 Article 23(4)(a)Early warning24 hoursBecoming aware of the significant incident
NIS2 Article 23(4)(b)Incident notification72 hoursBecoming aware of the significant incident
NIS2 Article 23(4)(d)Final reportOne monthSubmission of the incident notification
DORA, RTS on incident reporting Article 5Initial notification4 hours, capped at 24 hoursClassification as major, capped from awareness
DORA, RTS Article 5Intermediate report72 hoursThe initial notification
DORA, RTS Article 5Final reportOne monthThe latest intermediate report

NIS2 Article 23 is a sequence. A plan that models only the 24-hour early warning misses the 72-hour notification and the one-month final report. GDPR Article 34 adds a separate duty to communicate to affected individuals where the breach is likely to result in a high risk to their rights and freedoms.

Prerequisites

None of the following can be created during an incident.

  1. A named incident commander plus one deputy. The role holds two powers: authorising a production-affecting containment action, and starting a regulatory filing. At this team size the role belongs to a person the organisation actually employs, named in the plan.
  2. Response permissions granted in advance. Isolating a device in Microsoft Defender for Endpoint requires at least the Active remediation actions role, and access to the device based on the device group settings, both stated in Microsoft's response-actions documentation. Revoking sessions through Microsoft Graph PowerShell requires User.RevokeSessions.All, User.ReadWrite.All or Directory.ReadWrite.All. A missing role assignment discovered during a P1 costs the containment window.
  3. A Microsoft Entra ID P1 or P2 licence, or the sign-in export in step 1 of the containment script below will not run. Microsoft's guide to analysing activity logs with Microsoft Graph lists a P1 or P2 licence as a prerequisite, and documents the error returned without one as "tenant doesn't have premium license". On Entra ID Free the sign-in log is portal-only: download it as CSV or JSON from Monitoring and health, Sign-in logs, inside the 7-day window.
  4. An out-of-band channel that has been tested. The CISA #StopRansomware response checklist warns that after an initial compromise the actor may monitor the organisation's activity and communications, and instructs responders to isolate systems in a coordinated manner using an out-of-band method.
  5. The log retention windows written down, because evidence expires on a schedule the team does not control. The table below carries the Microsoft defaults.
  6. A written ransom-payment position and the cyber-insurance notification requirement, both held offline, both settled well before an incident.
  7. Draft notification text for the national CSIRT or competent authority, in the format that authority publishes. Member states run their own portals. The draft is written before the incident and filled in during it.
Log sourceDefault retention
Microsoft Entra sign-in and audit logs, Entra ID Free7 days
Microsoft Entra sign-in and audit logs, Entra ID P1 or P230 days
Risky sign-ins, Entra ID Free / P1 / P27 / 30 / 90 days
Microsoft 365 unified audit log, Audit (Standard)180 days
Unified audit log, Audit (Premium), Entra ID, Exchange, OneDrive, SharePoint1 year

Those figures come from the Microsoft Entra data retention reference and the Microsoft Purview auditing overview. An account compromise discovered on day 40 in an Entra ID Free tenant has no sign-in log left to reconstruct, while the one-month NIS2 final report is still outstanding. Routing sign-in and audit logs to storage or a workspace beforehand is the cheapest control in this runbook, and it belongs in the same pass as Microsoft 365 tenant hardening.

The operations-centre number, computed from your own inputs

Continuous single-analyst cover is 168 hours a week. Divided by a 40-hour week that is 4.2 full-time equivalents, before holiday, sickness, training, or a second pair of eyes on anything serious. Multiply 4.2 by the fully loaded annual cost of one analyst in your own labour market, add tooling and management overhead, and compare that against the cost of operating the runbook below. The number is yours; a euro figure published here would describe a different market.

Severity and routing sized for the team you have

SeverityExamplesRoutingTarget
P1Ransomware indicators, privileged account compromise, suspected mass exfiltrationPhone the incident commander, then the technical lead. Chat channels notify, they do not activate.Acknowledge under 15 min, first containment action under 60 min
P2Lateral movement indicators, malware on a production endpoint, credential phishing with a successful sign-inPage the on-call engineer, notify the incident commanderAcknowledge under 30 min, contained under 4 hours
P3Failed-login bursts, single endpoint detection, anomalous but unconfirmed behaviourTicket with a named ownerAcknowledge under 4 hours, resolved under 24 hours
P4Policy violations, low-fidelity detections, informational eventsDaily digest, reviewed by one named personReviewed within 5 business days

These are targets to set and then measure. A team of this size cannot honestly promise round-the-clock acknowledgement, so write the out-of-hours position down and let the thresholds reflect it.

Triage: seven questions, answered in writing

  1. What fired? Raw alert, source system, timestamp in UTC, indicators.
  2. Is it real? Known false positive, test activity, or confirmed.
  3. What is the scope? One identity, one device, one tenant, or several.
  4. Is personal data in scope? This answer starts the GDPR Article 33 clock, and it is the one most often deferred.
  5. What severity, and on what reasoning? Map to the matrix above and record why.
  6. Who has to be told? Internally by name; externally, which authority, which customer contract, which insurer.
  7. Which track? Standard playbook, bespoke response, or escalation to a retained forensics provider.

The output is a written record with a case identifier. NIST SP 800-61 Revision 3 frames incident response as part of continuous cybersecurity risk management rather than a self-contained lifecycle, and the written record is what carries an incident into that loop.

Containment: capture before you cut

Containment actions destroy the evidence that the post-incident report and the regulatory filing both need. The rule is a strict order: capture, then contain, then remediate. For an account compromise on Microsoft 365, the following runs that order in one pass.

powershell
# Account compromise: evidence first, containment second.
# Modules: Microsoft.Graph.Reports, Microsoft.Graph.Users,
#          Microsoft.Graph.Users.Actions, Microsoft.Graph.Identity.SignIns,
#          Microsoft.Graph.Applications
$upn  = 'suspect.user@contoso.com'
$case = 'INC-2026-0042'
$dir  = Join-Path (Get-Location) $case
New-Item -ItemType Directory -Path $dir -Force | Out-Null

Connect-MgGraph -Scopes 'AuditLog.Read.All','User.ReadWrite.All',
                        'User.RevokeSessions.All','Directory.Read.All',
                        'Application.ReadWrite.All',
                        'DelegatedPermissionGrant.ReadWrite.All'

# 1. Sign-in evidence, exported before anything else changes state.
#    Needs Entra ID P1 or P2. On Free this cmdlet returns a premium-licence
#    error and the only path is the CSV or JSON download in the Microsoft
#    Entra admin center, inside the 7-day Free retention window.
$since = (Get-Date).AddDays(-30).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ')
Get-MgAuditLogSignIn -All -Filter "userPrincipalName eq '$upn' and createdDateTime ge $since" |
  Select-Object createdDateTime, appDisplayName, ipAddress, clientAppUsed,
                conditionalAccessStatus, riskLevelAggregated |
  Export-Csv (Join-Path $dir 'signins.csv') -NoTypeInformation

# 2a. Consent persistence, user half. This endpoint returns only grants whose
#     principal is this user. Tenant-wide grants are absent from it.
$user = Get-MgUser -UserId $upn
Get-MgUserOauth2PermissionGrant -UserId $user.Id -All |
  Select-Object Id, ClientId, ResourceId, Scope |
  Export-Csv (Join-Path $dir 'oauth-grants-user.csv') -NoTypeInformation

# 2b. Consent persistence, tenant half: grants consented for all principals.
$tenantWide = Get-MgOauth2PermissionGrant -All -Filter "consentType eq 'AllPrincipals'"
$tenantWide | Select-Object Id, ClientId, ResourceId, ConsentType, Scope |
  Export-Csv (Join-Path $dir 'oauth-grants-tenant.csv') -NoTypeInformation

# 2c. Application permissions held by those same service principals.
$tenantWide.ClientId | Sort-Object -Unique | ForEach-Object {
  Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $_ -All
} | Select-Object PrincipalDisplayName, ResourceDisplayName, AppRoleId |
  Export-Csv (Join-Path $dir 'app-role-assignments.csv') -NoTypeInformation

# 3. Containment of the consent path. Fill both arrays by hand from the three
#    CSVs above. Nothing here guesses which application is hostile.
$hostileGrantIds = @()
$hostileAppIds   = @()
foreach ($id in $hostileGrantIds) {
  Remove-MgOauth2PermissionGrant -OAuth2PermissionGrantId $id -Confirm:$false
}
foreach ($id in $hostileAppIds) {
  Update-MgServicePrincipal -ServicePrincipalId $id -AccountEnabled:$false
}

# 4. Containment of the identity. Disabling the account and revoking sessions
#    are both critical events for continuous access evaluation.
Update-MgUser -UserId $upn -AccountEnabled:$false
Revoke-MgUserSignInSession -UserId $upn

# 5. Record the actions, the time, and the operator who took them.
[pscustomobject]@{
  case          = $case
  subject       = $upn
  grantsRemoved = $hostileGrantIds
  appsDisabled  = $hostileAppIds
  disabledUtc   = (Get-Date).ToUniversalTime().ToString('o')
  operator      = (Get-MgContext).Account
} | ConvertTo-Json | Out-File (Join-Path $dir 'containment.json')

Step 2 has two halves because Microsoft's reference for a user's oauth2PermissionGrants states that the query returns only grants specifically for the given user, and that grants made on behalf of all users in the organisation are not included. An empty oauth-grants-user.csv is therefore no evidence of a clean tenant: the sweep in 2b and the application permissions in 2c are where an illicit-consent attack leaves its highest-impact grant.

Step 3 closes the path that credential remediation leaves open. Microsoft's refresh-token revocation table shows that a password change made by the user, and an admin password reset from the Azure portal, both leave confidential-client refresh tokens alive, while a reset from the Microsoft Entra admin center or the Microsoft 365 admin center revokes them. Application permissions are unaffected by anything done to the user's credentials, and the grant object survives all of it, so a re-enabled account restores the attacker's app access with no fresh consent prompt. Deleting the grant revokes the access it carried, though Microsoft documents that access tokens already issued stay valid for their lifetime.

For a device, use the isolation action in Microsoft Defender for Endpoint rather than pulling power. Microsoft documents that isolation disconnects the device from the network while retaining connectivity to the Defender service, so telemetry keeps flowing. CISA's checklist adds taking the network offline at switch level when several subnets are affected, and snapshotting cloud volumes for forensic review. It lists system memory and firewall log buffers among the volatile evidence to preserve, which is why isolation beats a shutdown.

Expected output

The case directory holds five artefacts: signins.csv, oauth-grants-user.csv, oauth-grants-tenant.csv, app-role-assignments.csv and containment.json. The expected output of the triage and containment phase as a whole is one incident record that the internal report and every regulatory stage are views onto. Leave a deadline field blank until the event that starts it has happened.

yaml
incident_id: INC-2026-0042
severity: P1
aware_utc: 2026-05-17T02:34:12Z          # starts GDPR and NIS2 clocks
classified_major_utc:                    # blank until the DORA test is applied
classification:
  type: account_compromise
  scope: single_privileged_account
  personal_data_in_scope: probable
reporting:
  gdpr_art33_due: 2026-05-20T02:34:12Z   # aware + 72h
  nis2_early_warning_due: 2026-05-18T02:34:12Z
  nis2_notification_due: 2026-05-20T02:34:12Z
  nis2_final_due:                        # notification + 1 month
  dora_initial_due:                      # classification + 4h, capped aware + 24h
  dora_intermediate_due:                 # initial notification + 72h
  dora_final_due:                        # latest intermediate + 1 month
response_team:
  incident_commander: ic@contoso.com
  technical_lead: techlead@contoso.com
  comms_lead: comms@contoso.com
evidence:
  - INC-2026-0042/signins.csv
  - INC-2026-0042/oauth-grants-user.csv
  - INC-2026-0042/oauth-grants-tenant.csv
  - INC-2026-0042/app-role-assignments.csv
  - INC-2026-0042/containment.json
timeline:
  - { utc: 02:34, action: alert_received, source: defender_xdr }
  - { utc: 02:38, action: triage_started, owner: ic }
  - { utc: 02:52, action: evidence_export_complete }
  - { utc: 02:55, action: account_disabled_sessions_revoked }

Side effects

Every action above has consequences that are documented and therefore predictable.

  • Session revocation is not instant lockout. Microsoft's cmdlet reference describes it as invalidating refresh tokens and browser session cookies; access tokens already issued remain valid until they expire. Microsoft documents the default access token lifetime as one hour for clients that do not negotiate continuous access evaluation, and up to 28 hours for sessions that do, where revocation is instead driven by critical events with propagation latency of up to 15 minutes. Administrator revocation of refresh tokens and account disable are both such critical events. Guest accounts are not covered by continuous access evaluation at all.
  • Device isolation has a blast radius. Microsoft notes that in environments using web proxies, including PAC, WPAD or static proxy configurations, devices might not recover from full isolation, and recommends selective isolation there. Isolating a server running Hyper-V blocks network traffic to all of its child virtual machines. If the device is offline the action retries for up to three days, and isolation is automatically lifted after seven days, so a case left open past a week quietly reconnects the device.
  • Re-enabling an account is slow downstream. Microsoft gives a typical delay of about 15 minutes for SharePoint Online and Teams and 35 to 40 minutes for Exchange Online before a re-enabled account is recognised. Time the user communication to those delays.
  • Removing a consent grant breaks the application for every principal that grant covered. A grant with consentType AllPrincipals covers the whole tenant, so deleting it stops the application working for users who had nothing to do with the incident, and disabling a service principal blocks all sign-in and authentication by that application tenant-wide. That is why the export in step 2 is taken before the removal in step 3, and why both arrays in step 3 are filled by hand.
  • Broad disabling of remote access removes the responder's own path in. CISA's checklist does list disabling VPNs, remote access servers, single sign-on resources and public-facing assets for credential-based compromise. Sequence it only after the out-of-band channel is confirmed working and one administrator retains a verified route to the tenant.

Rollback

  • Device isolation: the button on the device page changes to Release from isolation, and the same permissions apply. Isolation also lapses on its own after seven days, which is a rollback nobody chose, so close or renew the action deliberately.
  • Disabled account: Update-MgUser -UserId $upn -AccountEnabled:$true, then allow for the downstream delays above.
  • Removed consent grant: restoring access requires a fresh consent, and that consent is admin-gated if the tenant restricts user consent, so the application does not simply resume once the incident closes. A disabled service principal is re-enabled with Update-MgServicePrincipal -ServicePrincipalId $id -AccountEnabled:$true.
  • Session revocation cannot be rolled back and does not need to be. Affected users re-authenticate, and multifactor re-enrolment should follow if the second factor itself is suspect.
  • Not reversible at all: a deleted account, so disable and never delete during an incident; an overwritten disk, so image before reimaging; and a filed notification, which is corrected through the next stage report rather than withdrawn. The staged structure of NIS2 Article 23 and of the DORA reports exists precisely because the first filing is made on incomplete information.
  • Recovery restores: restore to a rebuilt or known-clean host from a backup that pre-dates the earliest confirmed compromise timestamp, rather than one whose hashes merely match. Confirm the repository was offline or immutable throughout the dwell period. CISA advises treating immutable storage with care, since misconfiguration carries real cost and it does not satisfy every regulatory criterion by itself.

Limitations

This runbook assumes Microsoft 365 with Entra ID and Defender for Endpoint. On Google Workspace the sequence holds but every command changes. It does not cover compromise of an on-premises Active Directory forest, which needs a tier-0 recovery plan of its own, and it stops where an incident involves confirmed exfiltration at scale, encrypted production systems, or a domain controller: there a retained forensics provider and legal counsel lead the response.

The reporting table states the deadlines set by the EU instruments, not the national procedure. NIS2 is transposed member state by member state, the competent authority and the reporting portal are national, and sectoral rules may add duties. Confirm the destination and format with the national CSIRT before an incident. The DORA rows apply only to financial entities in scope of that regulation, and the four-hour clock does not begin until the incident is classified as major against the DORA classification standards, a judgement this runbook does not make for you.

Nothing here reports an outcome. The severity targets are thresholds to set and then measure against your own record; the retention and token-lifetime figures are vendor defaults that a tenant can change and that Microsoft revises. Verify them against your own configuration, for example with the M365 Security Scorecard, before writing them into a plan.

Last verified 2026-07-28. Reporting stages checked against NIS2 Article 23, GDPR Article 33, and Article 5 of the DORA regulatory technical standards on incident reporting. Command syntax, Graph scopes, the Entra ID P1 or P2 requirement on the sign-in reporting API, the scope limits of the per-user consent-grant query, refresh-token revocation behaviour, token lifetimes, isolation behaviour and log retention checked against current Microsoft Learn documentation. Containment sequencing checked against the CISA #StopRansomware response checklist and NIST SP 800-61 Revision 3.

Sources and further reading

Was this field note useful?
Apply the runbook

Turn the procedure into a tenant decision.

The Architecture Workshop maps the checks, side effects, and rollback path to your own Microsoft 365 environment.

Review the workshop