Writing a SOC Playbook an Analyst Will Follow at 3 a.m.
What separates a SOC playbook analysts follow from a document that rots in a wiki: every step names a tool and a query, every branch carries a threshold.

A SOC playbook is a short, alert-specific procedure that tells an analyst what to check, in which tool, and what to do with each answer. It works when every step is executable, meaning it names the tool and gives you the query, and decidable, meaning it ends in a branch with a threshold. Everything else in the document is context.
The document nobody opens
The usual failure looks like this. Someone senior writes twenty playbooks during a quiet fortnight, one per attack technique they could name, and files them in the wiki. Six months later a tier-1 analyst gets a brute force alert at 03:12, opens the brute force document, and finds a paragraph explaining what brute force is, a bullet list saying to review the logs and determine whether the activity is malicious, and a note to escalate if appropriate. They close the tab and ask the person on call.
Nothing in that document was wrong. It was just not a procedure. It was an explanation of a topic wearing the shape of one, and that gap is where most playbook programmes die.
A playbook has one job: compress the distance between an alert appearing and a defensible decision being written, and do it consistently enough that two analysts working the same alert reach the same verdict. Consistency is what makes your handovers survivable and your false positive rate a number that means something.
The cost is real, and most articles on this subject skip it. Writing one properly means running the searches yourself, finding out which fields your deployment populates, discovering that the field name in the vendor documentation is not the field name in your index, and deciding the thresholds. Then it decays. Detections get tuned, tools get replaced, and every query you wrote quietly stops returning rows. A playbook set is a maintained asset, not a document you finish.
One boundary before we go further. Playbooks run after triage has decided what the alert is. Triage sorts the queue and answers whether something deserves investigation at all. The playbook is what you open once the answer is yes. Blurring the two produces a document that tries to be both a queue-sorting heuristic and an investigation procedure, and is neither.
Four documents that get called the same thing
Search for "SOC playbook" and you get results describing four genuinely different artifacts. They overlap, the vocabulary is contested, and teams lose real hours arguing about it. Here is a split that holds up in practice.
| Artifact | Organised around | Who reads it | Length of one run | Failure mode |
|---|---|---|---|---|
| Investigation (SOC) playbook | One alert or incident type | Tier-1 and tier-2 analysts, live | Minutes | Steps too vague to act on |
| Runbook | One operational task | Whoever owns the system | Minutes to hours | Assumes access the reader does not have |
| SOAR playbook | An automated workflow | Nobody, until it breaks | Seconds | Silent failure on an edge case |
| Incident response plan | The organisation | Leadership, legal, comms, IR lead | Days to weeks | Written for an auditor, not for an incident |
The runbook distinction is the one people fight about hardest, and the honest answer is that the industry has never settled it. Mature teams call everything a runbook; others call everything a playbook. Neither is wrong. What matters is that your shop picks one convention, writes it down where the new hire will find it, then judges each document by a single question: who opens this, and what pressure are they under when they do? An analyst mid-alert and an engineer restoring a broken collector need different documents.
The SOAR playbook is a different animal. It is machine-executed, so it cannot ask for judgement, and its failure mode is silence: it runs, takes a branch nobody anticipated, and closes a ticket that should have been escalated. Automation earns its keep on the enrichment steps at the top of an investigation playbook, the pure lookups. It does not replace the middle of the document, where an analyst weighs two pieces of evidence that disagree.
Where the published examples sit
Three widely cited sources come up whenever someone starts writing playbooks, aimed at three different layers.
CISA publishes a federal incident and vulnerability response playbook set, and its incident response process runs five phases: Preparation, Detection and Analysis, Containment, Eradication and Recovery, and Post-Incident Activities. That is an organisation-level process describing how an agency coordinates itself through an incident. It is not what your tier-1 analyst opens when a single impossible-travel alert fires, and using it as a per-alert template produces a five-phase document about one sign-in.
NIST SP 800-61 is the source of the lifecycle everybody quotes, and this is worth getting right because most published playbook advice has not caught up. The four-phase lifecycle (preparation, detection and analysis, containment/eradication/recovery, post-incident activity) comes from Revision 2, published on 6 August 2012. Revision 3 arrived in April 2025 and supersedes it, under the title "Incident Response Recommendations and Considerations for Cybersecurity Risk Management: A CSF 2.0 Community Profile". The reframing is the point: incident response is presented through the CSF 2.0 functions rather than as a standalone four-box lifecycle. If your playbook template has a diagram of four phases with a loop arrow, it is quoting a document NIST replaced. Your auditor will notice eventually, and it tells you how much of the surrounding advice was copied rather than checked.
Microsoft publishes incident response playbooks for phishing, password spray, app consent grant and token theft. This is the vendor-shaped playbook: genuinely good inside that product, precise about which tables and portals to use, and tied to it. If you run that stack, start there and adapt. If you do not, the structure still teaches you something even though every query needs rewriting. Copy the specificity, not the field names.
The anatomy of a step that survives contact
We publish a set of investigation playbooks here, so rather than describe an abstract schema, here is ours, counted today.
Fifteen playbooks across six categories. Seventy-five investigation steps, four to six per playbook. Fifty-four carry at least one query, so twenty-one do not: those are the containment, remediation and documentation steps where the work is an action rather than a search. Underneath sit 78 distinct logical queries, each written three times, in SPL, KQL and Lucene, because a playbook whose queries only run in one product has to be rewritten from scratch when the team migrates tools. Across the set: 46 escalation criteria, 60 entries in the "common mistakes" fields, and 26 distinct ATT&CK technique IDs.
Seventeen of the 75 steps carry an explicit decision branch. Fewer than a quarter. Every one of the fifteen playbooks has at least one, but most steps do not.
That is deliberate, and the opposite of what a template-driven writer produces. Force a branch onto every step and you get fake forks that read "if you found something, continue; if not, continue". Real forks are rare. They happen where the answer to one question sends you down a materially different path: a confirmed compromise instead of a failed attempt, a credential-stuffing pattern instead of a single-account attack. Everything else is evidence gathering, and evidence gathering does not branch, it accumulates.
Take that as one corpus, ours, not as an industry benchmark. It still points at where the writing effort belongs: the few steps that actually fork.
The per-step schema is deliberately small:
titleanddescription: what you are answering and why it matters, in the fewest words that work.tools: which surface answers it, one of SIEM, XDR or firewall. This field exists because "check the logs" is the most common way a step fails. Naming the surface forces the writer to admit whether the data is there.siem_queries: the same logical question in SPL, KQL and Lucene.decision: optional, and when present it is acondition, anif_trueand anif_false. All three are mandatory once you open that door. A branch with only a true arm is a suggestion.
At the playbook level: an answer-first summary so a reader knows the shape of the work before committing, a when_you_see_this trigger list, the ordered steps, common_mistakes, escalation_criteria, and related ATT&CK technique IDs. That last field earns its place in aggregate rather than per document. Seeing T1558 on the Kerberoasting playbook tells an analyst little they did not know, but seeing which of the 26 techniques your set touches, and which parts of the ATT&CK matrix it does not, is a coverage conversation worth having.
The two fields teams skip pay off fastest. common_mistakes is where you put what your senior analyst says out loud every time someone gets this alert wrong. On the phishing playbook, that is failing to search for the other recipients, because one user reporting a mail usually means dozens received it. escalation_criteria stops the two opposite failures: the analyst who escalates everything, and the one who quietly closes a real incident at 4 a.m. rather than waking someone up. Write it as conditions. On the ransomware playbook, "domain controller compromise, so the whole Active Directory environment is exposed" is a criterion. "It looks serious" is not.
One playbook, written out
Here is brute force, end to end, in the form I would want on screen at 3 a.m. The full version lives at the brute force investigation playbook; this is the reasoning behind its shape.
Triggers. Excessive failed authentications from one source. Simultaneous lockouts across multiple accounts. Hundreds of failures followed by a single success. An IDS or identity-provider alert naming password spraying.
Step 1. Establish scope and source. You need three numbers before anything else: how many failures, from which source, against how many distinct accounts. In Splunk:
index=auth action=failure earliest=-24h
| stats count AS failures, dc(user) AS accounts, values(app) AS apps,
min(_time) AS first_seen, max(_time) AS last_seen BY src_ip
| where failures > 20
| convert ctime(first_seen) ctime(last_seen)
| sort -failuresThe same question against Entra sign-in logs, where a non-zero ResultType is the failure condition:
SigninLogs
| where TimeGenerated > ago(24h)
| where ResultType != 0
| summarize Failures = count(), Accounts = dcount(UserPrincipalName),
FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated)
by IPAddress
| where Failures > 20
| order by Failures descIf the summarize and dcount pipeline is unfamiliar, our KQL walkthrough covers the operators these searches lean on.
Output shaped like this is what the next step reads:
| src_ip | failures | accounts | first_seen | last_seen |
|---|---|---|---|---|
| 10.14.22.7 | 412 | 1 | 02:51:04 | 03:19:47 |
| 203.0.113.90 | 88 | 61 | 01:12:20 | 03:40:11 |
| 10.9.4.31 | 31 | 1 | 09:02:11 | 09:04:55 |
Simulated example generated by SOCSimulator Research.
Three rows, three different investigations. The first is a classic single-account attack, internal source, half an hour of sustained failures. The second is 88 attempts spread across 61 accounts, which is not brute force at all. The third is somebody back from leave after a password rotation.
Note what the > 20 is doing. It is a starting filter, not a finding, and the number most likely to be wrong in your environment. Derive it: run the aggregation without the where clause for a fortnight and set the floor above your normal noise. A threshold you copied from an article is one you cannot defend in a post-incident review.
Step 2. Did anything succeed? This is the question the whole playbook exists to answer, and the one that gets skipped, because failed-login dashboards are hypnotic and success events sit in a different search.
index=auth src_ip="10.14.22.7" action=success earliest=-24h
| stats min(_time) AS first_success, count AS sessions BY user, app
| convert ctime(first_success)SigninLogs
| where TimeGenerated > ago(24h)
| where IPAddress == "10.14.22.7" and ResultType == 0
| summarize FirstSuccess = min(TimeGenerated), Sessions = count()
by UserPrincipalName, AppDisplayNameThe branch.
Condition: at least one successful authentication from the source IP inside the window, or a success on a targeted account from any new source after the failure burst began.
If true: confirmed compromise, not a failed attempt. Disable or force-reset the account, revoke sessions and refresh tokens, escalate to incident response. The investigation is now about what happened after the success.
If false: no access was gained. Block or rate-limit the source, confirm the lockout policy engaged, finish the documentation. This does not get escalated.
That is what decidable means: the condition is checkable with the query directly above it, both arms exist, and each names an action rather than a mood.
On Windows domain authentication, add one qualifier to the true arm, because not every success is equal. A successful logon type 3 against a logon type 10 is the difference between a network share being touched and somebody sitting on an interactive remote session. Both matter, and they do not get the same 3 a.m. response.
Step 3. Classify the shape. Rows one and two above are different attacks firing the same alert.
index=auth action=failure earliest=-24h
| stats dc(user) AS accounts, count AS attempts BY src_ip
| eval per_account=round(attempts/accounts,1)
| where accounts > 5 AND per_account <= 5More than five distinct accounts at five or fewer attempts each is spraying or credential stuffing, and it changes the response. Blocking the source is nearly pointless against an attacker rotating through residential proxies, and the real exposure is a password list rather than one account. Containment becomes a password reset across the targeted set plus a hard look at MFA coverage. The threshold is yours: five is reasonable against a lockout policy set at ten, and wrong if yours is set at three.
Steps 4 and 5. Contain, then document. Neither carries a query, and that is fine. Containment names the firewall action, the identity action, and who is authorised to perform each. Documentation records the timeline, the source, the targeted accounts and the outcome, plus what should change so the alert is cheaper next time.
Five steps. One branch that matters, one classification threshold, two queries per investigative step, and no sentence anywhere that says "investigate further".
Six ways a playbook dies
Warning
Every one of these produces a document that passes review. They are not writing errors a proofreader catches. They are structural, and they show up only when somebody follows the thing under time pressure.
The step that says "investigate". Any imperative that does not name a data source is a hole. "Review the logs", "check for anomalies", "determine whether the activity is malicious". That is the writer handing the hard part back to the reader, which is the opposite of what a playbook is for. The repair is mechanical: for each vague step, ask what you would type, then paste that.
The branch with no threshold. "If the volume is unusual" and "if the behaviour is suspicious" are not decidable. Somebody has to pick the number, and if the playbook does not, each analyst picks a different one silently and your verdicts stop being comparable. When you genuinely do not know the number yet, say so. "Threshold not yet baselined, use judgement and record what you used" is honest and produces the data to fix it. A fake threshold does not.
The step that needs a tool tier-1 cannot reach. The playbook says to pull the packet capture, and the analysts who work this alert have no licence for the capture platform. Or it says to block at the perimeter, and only the network team can do that, and they are not on call. Access and authority are part of the step. If one requires a licence, a role or a phone call, say who and how, or the procedure stalls at exactly the step that mattered.
The playbook nobody has run since the SIEM migration. The quiet killer. The index was renamed, a sourcetype changed, a field sits one level deeper, and every search returns zero rows. Zero rows is worse than an error, because it looks like a clean result. An analyst who follows a broken playbook to a wrong "nothing found" conclusion learns not to trust the folder, and that lesson generalises to every other document in it.
The document that duplicates the incident response plan. Somebody adds regulatory notification timelines to the ransomware playbook, then to the exfiltration playbook, then to the business email compromise one. Now the requirement lives in four places, three of which will go stale. Governance content belongs at the plan layer, and the playbook links to it.
Coverage counted in documents. A team reports "we have thirty playbooks" and feels covered. Rank last quarter's closed alerts by rule name and you usually find a short head and a long tail, with the thirty documents distributed by what felt important rather than by what fires. A DNS tunneling playbook is worth having and is not what your queue is made of. Write coverage as a percentage of alert volume served, not a count of files.
How to write your first one
In order, starting from data you already have.
- Pull the alert volume. Last quarter, closed alerts grouped by detection rule name, sorted descending. If you can get median handling time too, multiply the two and sort by that: the cost of a rule is volume times minutes.
- Take the top rule, not the scariest one. The instinct is to write the nation-state scenario first. Resist it. The rule at the top of that list is the one your team works while tired, and it is where consistency is worth the most.
- Write the triggers before the steps. Listing every condition under which the playbook applies is what stops it turning into an essay about the attack type. If you cannot write four or five concrete triggers, the scope is wrong.
- Write the ending next, then work backwards. What are the possible verdicts? True positive, benign true positive, false positive, escalate. Once the endings are fixed, each step becomes a question that narrows between them, far easier to write than a list of things to check.
- Run every step yourself on a real closed alert, and paste what you typed. Not what the vendor documentation calls the field. What your deployment returned.
- Put a number on every branch. If you cannot defend it, mark it unbaselined and open a ticket to measure it. Do not invent one to look finished.
- Have someone else run it cold. Give a colleague the playbook and an alert they have not seen, and watch without helping. Every hesitation is a defect. Half an hour of this catches more than any review round.
- Ship it before it is finished. A playbook at eighty percent that gets used beats a perfect one still in draft, because contact with real alerts is what tells you which parts were wrong.
Keeping them alive
Ownership first: one named person per playbook, not a team and not a distribution list. Shared ownership means the query breaks and everybody assumes somebody else noticed.
Then stop reviewing on a calendar. Annual reviews catch drift eleven months late and turn into a signature exercise. Review on events instead, and only a handful are worth wiring up:
- The detection logic behind the alert changed. New rule, new tuning, new threshold: the playbook that reads its output is now suspect.
- A tool was migrated, replaced or renamed, or field and index names moved. Every query in the affected playbooks needs re-running, not re-reading.
- An escalation path changed. New on-call rota, new IR provider, a role that no longer exists.
- A real incident went sideways in a way the playbook did not anticipate. The lesson usually goes into the post-incident report and never into the procedure.
What makes those triggers cheap is storing playbooks where the detections live. If the rule and the procedure that services it sit in the same repository, changing one prompts changing the other in the same review. That is the detection as code argument applied one layer up: the rule is versioned, so the response to it should be too. A wiki page has no diff, no reviewer, and no way to tell you it went stale.
Last, measure the right thing. Not the number of playbooks: what share of last month's closed alerts had one covering them, and how often the analyst opened it. The first tells you where to write next. The second tells you whether what you wrote is any good, and if it is low, the answer is almost never that analysts need reminding. The document failed the executable-and-decidable test and they found that out the hard way.
Note
A quick audit you can run today. Open any playbook, read only the imperative sentences, and mark each one E if it names a tool and a query, D if it ends in a stated condition, and X if it does neither. Count the X marks. That ratio is your playbook programme's real state, and it takes about ten minutes per document.
Free
Train on real alerts, with zero consequences
Practice triage on realistic alert volume in a live SOC console. Free.
Writing the document is the easy half. A playbook is a claim about your environment, and environments move: the query that returned rows in March returns nothing in September because somebody renamed an index and told the wrong channel. So the useful test is whether an analyst who has never seen this alert can open it at 3 a.m., run every step as written, and come out with a verdict they can defend in the morning. If they cannot, it is a topic explainer with numbered headings, and no amount of formatting fixes that.
Frequently Asked Questions
- What is a SOC playbook?
- A SOC playbook is a short procedure for one alert type that tells an analyst what to check, in which tool, and what to do with each answer. It covers the window between an alert firing and a verdict being written, usually minutes rather than hours. A good one is specific enough to paste from: it names the data source, carries the query, and ends each step in a branch with a stated threshold. It is not a policy document, and it is not the incident response plan.
- What is the difference between a playbook and a runbook?
- The industry does not agree, and the argument is less useful than it looks. The workable split: a playbook is organised around an alert or an incident type and produces a decision, while a runbook is organised around a task and produces a completed operation, such as restoring a log collector or rotating a certificate. Many shops use the words interchangeably. Pick one convention, write it down, and judge each document by who reads it under pressure rather than by its filename.
- What should a SOC playbook contain?
- Triggers that say when the playbook applies, an answer-first summary so a reader knows the shape of the work before starting, ordered investigation steps that each name a tool and carry a runnable query, explicit escalation criteria, and the mistakes analysts actually make on this alert type. Technique mappings help you spot coverage gaps across the set. Everything else is context, and context that nobody reads at 3 a.m. belongs in a linked reference rather than in the middle of the procedure.
- How many playbooks does a SOC need?
- Count alerts, not documents. Rank your closed alerts from the last quarter by rule name, and you usually find that a small number of rules produce most of the queue. Cover those first. A team with five playbooks that match the top five noisy detections is in better shape than a team with forty documents covering scenarios that fired twice last year. Coverage measured in documents is the metric that lets a folder look healthy while the queue goes unserved.
- How often should SOC playbooks be updated?
- Review on events, not on a calendar. The triggers that matter: the detection logic behind the alert changed, a tool was migrated or renamed, field or index names moved, an escalation path or on-call rota changed, or a real incident went sideways in a way the playbook did not anticipate. An annual review cycle catches none of these in time. A quarterly reminder is fine as a backstop, but the event triggers are what keep the queries runnable.
Field notes
New walkthroughs and detections, in your inbox
A short email when we publish something worth your time. No spam, unsubscribe in one click.
Community
Continue the conversation
Discuss this with analysts who are actively training and working in the field.
Related Articles

Web Shell Detection: How to Find One, and Why Most Rules Miss It
Triage and detection logic for web shells: the process-parent rule, its real false positives, IIS log tells, and an ordered first 30 minutes.

Windows Event IDs Cheat Sheet: The 31 That Matter
Windows event IDs cheat sheet for SOC analysts: 31 essential security event IDs covering auth, process execution, log tampering, and lateral movement.

Common Ports Cheat Sheet: 42 Ports SOC Analysts Memorize
Common ports cheat sheet for SOC analysts — master the 42 TCP/UDP ports that appear in firewall logs, SIEM alerts, and security interviews every single day.