Back to Field Notes
Security Operations/Field Note

Writing a Runbook That Holds Up at 3 a.m.

A runbook that requires reading three Confluence pages at 3 a.m. is not a runbook. The structure has to survive sleep deprivation, partial information, and the specific anxiety of not knowing whether the situation matches the playbook.

Author

Aisha Khan

Director, Threat Intelligence

Published

June 10, 2026

Read

11 min

Share
AI-generated illustration of a power grid substation
AI-generated illustration of a power grid substation
Key Takeaways
  • 01Runbooks fail at the moment they are needed most because they are written for the author, not the 3 a.m. on-call. The structure must be optimized for the reader under stress.
  • 02Seven blocks, in order: Trigger, Decide-this-is-it, Contain, Investigate, Decide-escalate, Recover, Close. Anything else is supplementary.
  • 03Cut all background, theory, and 'why this exists' content from the runbook itself. Link to it in a sidebar; it does not belong in the execution path.
  • 04Untested runbooks are documentation, not runbooks. Annual tabletop test minimum; quarterly is better; chaos-day exercises best.
  • 05The single best diagnostic for a runbook's quality: time how long it takes a new on-call to complete the runbook against a synthetic incident. If > 25% over expert time, the runbook needs work.

A runbook that requires the reader to context-switch through three different documentation systems at 3 a.m. is not a runbook. The structure has to survive sleep deprivation, partial information, and the specific anxiety of not knowing whether the current situation matches the playbook.

This piece is the runbook-writing standard we hand to clients during SOC reorganizations. It is short on theory and long on structure, because the only thing that matters is whether the on-call can execute it cold.

/FIELD_NOTE

Why most runbooks fail.

Most runbooks are written by an expert who lived through one incident, intending to capture what they did. The result reads beautifully to the author and unhelpfully to anyone else. The fix is to write the runbook for a competent on-call who has never seen this incident type before — a definition that includes the author six months from now.

The seven-block structure

Every block has one job and ends before it strays. The on-call should be able to scroll-stop on any block and know what they are doing.

/RUNBOOK · BLOCK_STRUCTURE

#BlockOne-sentence purpose
1TriggerWhat specific signal invokes this runbook
2Decide (is this it?)Quick yes/no checks: do I have the right runbook?
3ContainFirst actions to limit damage, in strict order
4InvestigateQueries with expected output; build the picture
5Decide (escalate?)Named criteria + named contacts; not 'page someone'
6RecoverRestoration steps with verification
7ClosePostmortem trigger + required artifacts

A worked example — phishing-derived credential compromise

Below is a complete runbook in the seven-block format. Notice how each block is short, executable, and assumes the reader is competent but tired.

/RUNBOOK · phishing-derived credential compromise

# 1 · TRIGGER
#   ITDR alert: "Stolen-session token replay (geo-mismatch)"
#     OR
#   IdP alert: "Successful sign-in from unknown ASN within 1h of MFA fatigue"
#     OR
#   User self-report through helpdesk → tagged 'phish-creds'

# 2 · DECIDE — is this the right runbook?
#   YES if all of:
#     ✓ Authenticated session in IdP / SaaS within last 24h
#     ✓ Source IP / fingerprint mismatch with prior 30d
#     ✓ NO laptop loss or theft reported (different runbook)

# 3 · CONTAIN  (do these in order, do NOT skip)
#   a. IdP: revoke all sessions for user_id   (UI / 'kill sessions')
#   b. IdP: require step-up + factor re-enroll on next sign-in
#   c. PAM: invalidate any cached creds for that user
#   d. SaaS:  invoke 'force re-auth' on Salesforce, M365, GitHub
#   e. Email: pull-back any sent mail in last 4h via journaling rule

# 4 · INVESTIGATE
#   Q1: SIEM > sourcetype=okta event=user.session.start user=$USER
#       earliest=-72h | stats count by ip,asn,fingerprint
#       expected: 1 ASN historically; 1 NEW ASN in last 24h
#   Q2: SIEM > sourcetype=ms365 user=$USER OperationName=*
#       earliest=-24h | stats count by Operation
#       expected: read-heavy normal, watch for *Forwarding*, *Send*
#   Q3: GitHub audit log: user=$USER action=oauth_authorization*
#       expected: 0 new oauth grants in window

# 5 · DECIDE — escalate?
#   ESCALATE TO: ir-on-call (page) + legal-on-call (page) IF any of:
#     - Any 'Forwarding' rule created in mailbox in window
#     - Any new OAuth app authorized in window
#     - Any GitHub repo deleted, secret accessed, or release published
#     - Any payment / wire-related M365 access in window
#   OTHERWISE: continue.

# 6 · RECOVER
#   a. Confirm user has re-enrolled phishing-resistant MFA
#   b. Issue temporary device-bound credentials only
#   c. Re-grant session ONLY after Q1 / Q2 / Q3 are clean
#   d. 7-day enhanced monitoring tag on user_id

# 7 · CLOSE
#   - Postmortem REQUIRED if escalation triggered
#   - Postmortem OPTIONAL if contained pre-escalation
#   - Required artifacts: SIEM exports for Q1-Q3, IdP audit, screenshots
#   - File ticket: phish-IOC update for security-awareness team

What to ruthlessly cut

Most runbooks bloat for the same reasons. Below is the cut list. If you find any of these in a runbook, remove them; link to a separate background doc if needed.

  • 01Background ('In 2023 we observed an increase in...')
  • 02Theory ('Phishing-derived credential compromise typically follows the kill chain...')
  • 03Justification ('We respond this way because the EDPB recommendation...')
  • 04Author voice ('When I worked through a similar incident...')
  • 05Anything in passive voice — execution steps must be imperative
  • 06Anything that says 'consider' instead of 'do' — decide once, write it once
/COMMON_FAILURE

The 'consider' trap.

When a runbook says 'consider notifying legal,' it is asking the on-call to make a decision under stress. Either the runbook should say 'page legal-on-call IF X' (with X concretely defined) or it should not mention legal at all. Decisions that the runbook author can make once, in calm, must not be deferred to an on-call at 3 a.m.

Test cadence — the only honest measure of runbook quality

An untested runbook is documentation. The test cadence below is what we recommend by runbook severity. Test failures are not embarrassing; they are the entire point of testing.

/RUNBOOK · TEST_CADENCE

Runbook severityMinimum cadenceTest type
Critical (data exfil, ransomware)QuarterlyTabletop + chaos-day execution
High (creds, internal lateral)Semi-annualTabletop
Medium (malware containment)AnnualTabletop
Low (lost device, policy violation)AnnualWalk-through review

Three quality KPIs for a runbook program

/RUNBOOK_PROGRAM_KPIS

KPITargetWhat it proves
New-on-call-vs-expert time ratio≤ 1.25Runbook is reader-optimized
Test pass rate (no edits required)≥ 80% per cycleRunbooks are kept current
Median age since last test≤ 12 monthsCadence discipline is real

A 30-day program

  1. 01Days 0–7 — Inventory all current runbooks. Tag by severity. Identify the top 10 most-invoked. Schedule their tests.
  2. 02Days 7–21 — Re-write the top 10 in the seven-block format. Cut bloat. Add expected outputs to every query.
  3. 03Days 21–30 — Run tabletops with on-calls who did not write the runbooks. Capture every place they paused, asked a question, or guessed. Fix those places before publishing.
/MONDAY_PLAYBOOK

Monday morning — the test that proves your runbook program is real.

Pick any runbook in your inventory at random. Hand it to an on-call who has not used it before. Time them through a synthetic invocation. If they finish within 25% of expert time without asking for help, the runbook is good. If not, you have your week's work — and a representative sample of how the rest of the inventory probably looks.

  • ▸Random-sample one runbook from your inventory
  • ▸Hand it cold to a new on-call against a synthetic incident
  • ▸Time them; tally pauses and questions
  • ▸Each pause = a future fix; each question = a future cut

Closing — runbooks are written for the worst night of the year

The on-call who picks up your runbook at 3 a.m. is competent, exhausted, and uncertain. The runbook's only job is to make their next 30 minutes safer than improvisation would have been. Seven blocks, no theory, no passive voice, queries with expected outputs, escalation criteria with named names, tested at a known cadence. That is the standard. Hold the line, and the worst night of the year becomes the night the runbook quietly did its job.

#Runbook#Operations#Documentation#Incident Response

/WRITTEN_BY

Aisha Khan

Director, Threat Intelligence · Alexa Cybersecurity