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.
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.
| Regime | Stage | Deadline | Measured from |
|---|---|---|---|
| GDPR Article 33 | Notification to the supervisory authority | 72 hours | Becoming aware of the personal data breach |
| NIS2 Article 23(4)(a) | Early warning | 24 hours | Becoming aware of the significant incident |
| NIS2 Article 23(4)(b) | Incident notification | 72 hours | Becoming aware of the significant incident |
| NIS2 Article 23(4)(d) | Final report | One month | Submission of the incident notification |
| DORA, RTS on incident reporting Article 5 | Initial notification | 4 hours, capped at 24 hours | Classification as major, capped from awareness |
| DORA, RTS Article 5 | Intermediate report | 72 hours | The initial notification |
| DORA, RTS Article 5 | Final report | One month | The 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.
- 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.
- 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.
- 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.
- 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.
- The log retention windows written down, because evidence expires on a schedule the team does not control. The table below carries the Microsoft defaults.
- A written ransom-payment position and the cyber-insurance notification requirement, both held offline, both settled well before an incident.
- 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 source | Default retention |
|---|---|
| Microsoft Entra sign-in and audit logs, Entra ID Free | 7 days |
| Microsoft Entra sign-in and audit logs, Entra ID P1 or P2 | 30 days |
| Risky sign-ins, Entra ID Free / P1 / P2 | 7 / 30 / 90 days |
| Microsoft 365 unified audit log, Audit (Standard) | 180 days |
| Unified audit log, Audit (Premium), Entra ID, Exchange, OneDrive, SharePoint | 1 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
| Severity | Examples | Routing | Target |
|---|---|---|---|
| P1 | Ransomware indicators, privileged account compromise, suspected mass exfiltration | Phone the incident commander, then the technical lead. Chat channels notify, they do not activate. | Acknowledge under 15 min, first containment action under 60 min |
| P2 | Lateral movement indicators, malware on a production endpoint, credential phishing with a successful sign-in | Page the on-call engineer, notify the incident commander | Acknowledge under 30 min, contained under 4 hours |
| P3 | Failed-login bursts, single endpoint detection, anomalous but unconfirmed behaviour | Ticket with a named owner | Acknowledge under 4 hours, resolved under 24 hours |
| P4 | Policy violations, low-fidelity detections, informational events | Daily digest, reviewed by one named person | Reviewed 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
- What fired? Raw alert, source system, timestamp in UTC, indicators.
- Is it real? Known false positive, test activity, or confirmed.
- What is the scope? One identity, one device, one tenant, or several.
- Is personal data in scope? This answer starts the GDPR Article 33 clock, and it is the one most often deferred.
- What severity, and on what reasoning? Map to the matrix above and record why.
- Who has to be told? Internally by name; externally, which authority, which customer contract, which insurer.
- 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.
# 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.
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
- NIST SP 800-61 Revision 3, Incident Response Recommendations and Considerations for Cybersecurity Risk Management
- Commission Delegated Regulation (EU) 2025/301, RTS on content and time limits for reporting major ICT-related incidents under DORA
- Regulation (EU) 2022/2554 (DORA), Article 19 reporting of major ICT-related incidents
- Directive (EU) 2022/2555 (NIS2), Article 23 reporting obligations
- Regulation (EU) 2016/679 (GDPR), Articles 33 and 34 personal data breach notification
- CISA #StopRansomware Guide, ransomware and data extortion response checklist
- Microsoft Learn: Take response actions on a device in Microsoft Defender for Endpoint
- Microsoft Learn: Continuous access evaluation in Microsoft Entra
- Microsoft Learn: Microsoft Entra data retention for audit and sign-in logs
- Microsoft Learn: Auditing solutions in Microsoft Purview, audit log retention
- Microsoft Learn: Revoke-MgUserSignInSession cmdlet reference
- Microsoft Learn: How to analyze activity logs with Microsoft Graph, prerequisites and common errors
- Microsoft Learn: How to download logs in Microsoft Entra ID
- Microsoft Learn: Refresh tokens in the Microsoft identity platform, token revocation table
- Microsoft Graph: List a user's oauth2PermissionGrants
- Microsoft Learn: Remove-MgOauth2PermissionGrant cmdlet reference
- Microsoft Learn: Disable user sign-in for an application, Microsoft Graph PowerShell
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 workshopMore from Ops Log
Mailbox forwarding rules survive the leaver: the offboarding check most runbooks skip
An enabled inbox forwarding or redirect rule keeps sending a departed employee mail long after the account is disabled. Here is how to find every one from Microsoft Graph and shut it before it becomes an exfiltration path.
The delegated OAuth grant that outlives the employee
Disabling an Entra account does not delete the delegated OAuth grants the person consented to. A third-party app can keep acting on a former employee until the grant itself is revoked. Here is how to read them and which scopes to treat as high risk.
DMARC at p=none is not protection: what a deliverability check reads from public DNS
A DMARC record at p=none observes spoofing without blocking it. A free deliverability check reads SPF, DKIM, and DMARC from public DNS and tells you exactly which of those three is only watching. Here is how to run it and read it.