This workflow corresponds to n8n.io template #16446 — we link there as the canonical source.
This workflow follows the Agent → Chainllm recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "gcQL6CuHB17OzWiN",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "[Template] AI Powered Incident Management",
"tags": [],
"nodes": [
{
"id": "334458ec-a24e-4033-a286-ac3dc8521d5f",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3840,
2256
],
"parameters": {
"color": 2,
"width": 4416,
"height": 1392,
"content": "# Ingestion Pipeline\n\nRun these pipelines ONCE before the first demo, and again whenever source data changes.\n\nEach pipeline is independent and can be run separately.\n\nRecommended order:\n 1) Ingest Resolved Incidents\n 2) Ingest Reference Playbooks\n 3) Ingest Test Incidents"
},
"typeVersion": 1
},
{
"id": "97c4f761-febf-4338-a1fd-f58cdabe82b7",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2896,
2448
],
"parameters": {
"color": 4,
"width": 448,
"height": 256,
"content": "## 1) Ingest Resolved Incidents\n\nSource: GitHub (Resolved Incidents/)\nTarget: resolved_incidents_v1 (vector table)\nEmbedding: Gemini models/gemini-embedding-001\n\nRe-run after adding or updating resolved\nincident JSON files."
},
"typeVersion": 1
},
{
"id": "ca2fb3f1-393e-42e7-9fea-6f41aeb2e542",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1216,
2768
],
"parameters": {
"color": 4,
"width": 448,
"height": 176,
"content": "## 2) Ingest Reference Playbooks\n\nSource: GitHub (Reference Playbooks/)\nTarget: reference_playbooks_v1 (vector table)\nEmbedding: Gemini models/gemini-embedding-001\n\nRe-run after adding new .md playbook files\n(e.g. ransomware, IAM credential compromise)."
},
"typeVersion": 1
},
{
"id": "9d63fedc-75ea-4715-bdda-29bd4fffe380",
"name": "Resolved Incidents Data Loader",
"type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
"position": [
-2448,
2624
],
"parameters": {
"options": {
"metadata": {
"metadataValues": [
{
"name": "=incident_id",
"value": "={{ $('Prepare Markdown Document & Metadata').item.json.metadata.incident_id }}"
},
{
"name": "severity",
"value": "={{ $('Prepare Markdown Document & Metadata').item.json.metadata.severity }}"
},
{
"name": "category",
"value": "={{ $('Prepare Markdown Document & Metadata').item.json.metadata.category }}"
},
{
"name": "affected_systems",
"value": "={{ $('Prepare Markdown Document & Metadata').item.json.metadata.affected_systems }}"
},
{
"name": "mitre_tactic_ids",
"value": "={{ $json.metadata.mitre_tactic_ids }}"
},
{
"name": "mitre_technique_ids",
"value": "={{ $json.metadata.mitre_technique_ids }}"
},
{
"name": "mitre_prevention_ids",
"value": "={{ $json.metadata.mitre_prevention_ids }}"
},
{
"name": "@timestamp",
"value": "={{ $json.metadata['@timestamp'] }}"
},
{
"name": "description",
"value": "={{ $json.metadata.description }}"
},
{
"name": "alert_source",
"value": "={{ $json.metadata.alert_source }}"
},
{
"name": "entities",
"value": "={{ $json.metadata.entities }}"
},
{
"name": "detection_gap",
"value": "={{ $json.metadata.detection_gap }}"
},
{
"name": "what_went_well",
"value": "={{ $json.metadata.what_went_well }}"
},
{
"name": "what_went_wrong",
"value": "={{ $json.metadata.what_went_wrong }}"
}
]
}
},
"jsonData": "={{ $('Prepare Markdown Document & Metadata').item.json.pageContent }}",
"jsonMode": "expressionData"
},
"typeVersion": 1
},
{
"id": "bbb9c6c0-c0aa-472e-9db0-17529fb339c8",
"name": "Gemini Embeddings (Resolved Incidents)",
"type": "@n8n/n8n-nodes-langchain.embeddingsGoogleGemini",
"position": [
-2160,
2624
],
"parameters": {
"modelName": "={{ $('Config-Ingestion').item.json.model_embedding }}"
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 1
},
{
"id": "58223e31-4441-4b14-870c-732dcb6cb456",
"name": "Get Reference Playbooks From GitHub",
"type": "n8n-nodes-base.httpRequest",
"position": [
-2304,
3008
],
"parameters": {
"url": "={{ $('Config-Ingestion').item.json.github_baseUrl + '/' + $('Config-Ingestion').item.json.github_repo + '/contents/Reference%20Playbooks' }}",
"options": {}
},
"executeOnce": true,
"retryOnFail": true,
"typeVersion": 4.4
},
{
"id": "1a6ccefd-01be-4a85-9d01-cbbd74bdf968",
"name": "Get Resolved Incidents from GitHub",
"type": "n8n-nodes-base.httpRequest",
"position": [
-3344,
3008
],
"parameters": {
"url": "={{ $('Config-Ingestion').item.json.github_baseUrl + '/' + $('Config-Ingestion').item.json.github_repo + '/contents/Resolved%20Incidents' }}",
"options": {}
},
"retryOnFail": true,
"typeVersion": 4.2,
"alwaysOutputData": false
},
{
"id": "74f99ed4-9051-4dbf-aad8-34f2cc376a78",
"name": "Download Reference Playbooks From GitHub",
"type": "n8n-nodes-base.httpRequest",
"position": [
-1952,
2944
],
"parameters": {
"url": "={{$json[\"download_url\"]}}",
"options": {}
},
"retryOnFail": true,
"typeVersion": 4.4
},
{
"id": "f3783cca-59f7-4803-a57f-be13ffc82945",
"name": "Download Resolved Incidents From GitHub",
"type": "n8n-nodes-base.httpRequest",
"position": [
-3120,
3008
],
"parameters": {
"url": "={{$json[\"download_url\"]}}",
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
}
},
"retryOnFail": true,
"typeVersion": 4.4
},
{
"id": "5ff4ebbc-e18c-4c67-9d05-cfd1ca08305c",
"name": "Prepare Markdown Document & Metadata",
"type": "n8n-nodes-base.code",
"position": [
-2896,
3008
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const data = $json;\n\n// -----------------------------\n// Metadata (STRICT \u2013 Only Requested Fields)\n// -----------------------------\nconst metadata = {\n \"@timestamp\": data[\"@timestamp\"] ?? null,\n incident_id: data.incident_id ?? null,\n severity: data.severity ?? null,\n category: data.category ?? null,\n type: data.type ?? null,\n\n affected_systems: Array.isArray(data.affected_systems)\n ? data.affected_systems\n : [],\n\n mitre_tactic_ids: Array.isArray(data.mitre_tactic_ids)\n ? data.mitre_tactic_ids\n : [],\n\n mitre_technique_ids: Array.isArray(data.mitre_technique_ids)\n ? data.mitre_technique_ids\n : [],\n\n mitre_prevention_ids: Array.isArray(data.mitre_prevention_ids)\n ? data.mitre_prevention_ids\n : [],\n\n // \u2705 New fields retained\n description: data.description ?? null,\n alert_source: data.alert_source ?? null,\n rule_name: data.rule_name ?? null,\n entities: typeof data.entities === 'object' ? data.entities : {},\n detection_gap: data.detection_gap ?? null,\n what_went_well: Array.isArray(data.what_went_well) ? data.what_went_well : [],\n what_went_wrong: Array.isArray(data.what_went_wrong) ? data.what_went_wrong : []\n};\n\n// Remove null/undefined only\nObject.keys(metadata).forEach(key => {\n if (metadata[key] === undefined || metadata[key] === null) {\n delete metadata[key];\n }\n});\n\n// -----------------------------\n// Markdown Content\n// -----------------------------\nconst sections = [];\n\n// Header\nsections.push(`# Incident: ${data.title ?? \"Untitled Incident\"}`);\nsections.push(`**Incident ID:** ${data.incident_id ?? \"N/A\"}`);\nsections.push(`**Severity:** ${data.severity ?? \"N/A\"}`);\nsections.push(`**Category:** ${data.category ?? \"N/A\"}`);\nsections.push(`**Type:** ${data.type ?? \"N/A\"}`);\nsections.push(`**Status:** ${data.status ?? \"N/A\"}`);\nsections.push(`**Date:** ${data[\"@timestamp\"] ?? \"N/A\"}`);\n\nif (Array.isArray(data.affected_systems) && data.affected_systems.length > 0) {\n sections.push(`**Affected Systems:** ${data.affected_systems.join(\", \")}`);\n}\n\n// Alert Source\nif (data.alert_source) {\n sections.push(\"\");\n sections.push(\"## Alert Source\");\n sections.push(`**Detection Tool:** ${data.alert_source}`);\n if (data.rule_name) {\n sections.push(`**Rule/Finding:** ${data.rule_name}`);\n }\n}\n\n// Entities (clean + safe)\nconst entities = metadata.entities;\n\nif (\n entities &&\n typeof entities === 'object' &&\n Object.keys(entities).length > 0\n) {\n const entityLines = [];\n\n if (Array.isArray(entities.users) && entities.users.length > 0)\n entityLines.push(`**Users:** ${entities.users.join(', ')}`);\n\n if (Array.isArray(entities.ips) && entities.ips.length > 0)\n entityLines.push(`**IPs:** ${entities.ips.join(', ')}`);\n\n if (Array.isArray(entities.hosts) && entities.hosts.length > 0)\n entityLines.push(`**Hosts:** ${entities.hosts.join(', ')}`);\n\n if (Array.isArray(entities.domains) && entities.domains.length > 0)\n entityLines.push(`**Domains:** ${entities.domains.join(', ')}`);\n\n if (Array.isArray(entities.hashes) && entities.hashes.length > 0)\n entityLines.push(`**Hashes:** ${entities.hashes.join(', ')}`);\n\n if (entityLines.length > 0) {\n sections.push(\"\");\n sections.push(\"## Entities\");\n entityLines.forEach(l => sections.push(l));\n }\n}\n\n// Description\nif (data.description) {\n sections.push(\"\");\n sections.push(\"## Description\");\n sections.push(data.description);\n}\n\n// Detection Gap\nif (data.detection_gap) {\n sections.push(\"\");\n sections.push(\"## Detection Gap\");\n sections.push(data.detection_gap);\n}\n\n// Timeline (safe)\nif (Array.isArray(data.timeline) && data.timeline.length > 0) {\n sections.push(\"\");\n sections.push(\"## Timeline\");\n\n data.timeline.slice(0, 50).forEach(t => {\n if (t && t.timestamp && t.event) {\n sections.push(`- ${t.timestamp} \u2014 ${t.event}`);\n }\n });\n}\n\n// Root Cause\nif (data.root_cause_analysis) {\n sections.push(\"\");\n sections.push(\"## Root Cause\");\n sections.push(data.root_cause_analysis);\n}\n\n// What Went Well\nif (Array.isArray(data.what_went_well) && data.what_went_well.length > 0) {\n sections.push(\"\");\n sections.push(\"## What Went Well\");\n data.what_went_well.forEach(item => sections.push(`- ${item}`));\n}\n\n// What Went Wrong\nif (Array.isArray(data.what_went_wrong) && data.what_went_wrong.length > 0) {\n sections.push(\"\");\n sections.push(\"## What Went Wrong\");\n data.what_went_wrong.forEach(item => sections.push(`- ${item}`));\n}\n\n// Resolution Summary\nif (data.resolution_summary) {\n sections.push(\"\");\n sections.push(\"## Resolution Summary\");\n sections.push(data.resolution_summary);\n}\n\n// Remediation Actions\nif (Array.isArray(data.remediation_actions) && data.remediation_actions.length > 0) {\n sections.push(\"\");\n sections.push(\"## Remediation Actions\");\n data.remediation_actions.forEach(action => {\n sections.push(`- ${action}`);\n });\n}\n\n// Lessons Learned\nif (data.lessons_learned) {\n sections.push(\"\");\n sections.push(\"## Lessons Learned\");\n sections.push(data.lessons_learned);\n}\n\n// MITRE Mapping (safe)\nconst mitre = [];\n\nif (Array.isArray(metadata.mitre_tactic_ids) && metadata.mitre_tactic_ids.length > 0)\n mitre.push(`Tactics: ${metadata.mitre_tactic_ids.join(\", \")}`);\n\nif (Array.isArray(metadata.mitre_technique_ids) && metadata.mitre_technique_ids.length > 0)\n mitre.push(`Techniques: ${metadata.mitre_technique_ids.join(\", \")}`);\n\nif (Array.isArray(metadata.mitre_prevention_ids) && metadata.mitre_prevention_ids.length > 0)\n mitre.push(`Prevention: ${metadata.mitre_prevention_ids.join(\", \")}`);\n\nif (mitre.length > 0) {\n sections.push(\"\");\n sections.push(\"## MITRE Mapping\");\n sections.push(mitre.join(\"\\n\"));\n}\n\n// Final Output\nconst pageContent = sections.join(\"\\n\");\n\nreturn {\n json: {\n pageContent,\n metadata\n }\n};"
},
"executeOnce": false,
"retryOnFail": true,
"typeVersion": 2,
"alwaysOutputData": false
},
{
"id": "2afcc845-1303-42f9-931d-baeb068b840e",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3840,
3760
],
"parameters": {
"color": 5,
"width": 4624,
"height": 1584,
"content": "# Retrieval & Response Workflow\n\nThis is the main pipeline. It processes one test incident\nend-to-end through three parallel intelligence branches\nand produces a structured JSON response report.\n\nFull flow:\n Step 1 --> Fetch Incident from Supabase\n Step 2 --> Parallel Retrieval (3 branches simultaneously)\n Step 3 --> Merge All Intelligence\n Step 4 --> Synthesize Report\n Step 5 --> Validate Output (If node)\n Step 6 --> Write to Supabase (or skip if degraded)\n\nConfigure the incident to process in the Set Incident ID node."
},
"typeVersion": 1
},
{
"id": "63cb4b2d-249d-4c9e-bb1c-cc37315b1ade",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-672,
2768
],
"parameters": {
"color": 4,
"width": 416,
"height": 176,
"content": "## 3) Ingest Test Incidents\n\nSource: GitHub (Test Incidents/)\nTarget: test_incidents_v1 (flat table)\n\nRe-run after updating test incident JSON files.\nClears and re-inserts all 13 rows."
},
"typeVersion": 1
},
{
"id": "45073f01-633f-4f16-9648-9ea80c422179",
"name": "Create a Row of Test Incident on Supabase",
"type": "n8n-nodes-base.supabase",
"position": [
-208,
3008
],
"parameters": {
"tableId": "={{ $('Config-Ingestion').item.json.table_test }}",
"dataToSend": "autoMapInputData"
},
"credentials": {
"supabaseApi": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 1
},
{
"id": "87c836df-fb31-4a6e-8b34-ba61f937c11e",
"name": "Gemini Embeddings (Playbooks Ingestion)",
"type": "@n8n/n8n-nodes-langchain.embeddingsGoogleGemini",
"position": [
-864,
3232
],
"parameters": {
"modelName": "={{ $('Config-Ingestion').item.json.model_embedding }}"
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 1
},
{
"id": "73966a1f-24b6-44db-ae8e-0d5aab353f79",
"name": "Reference Playbooks Data Loader",
"type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
"position": [
-1152,
3232
],
"parameters": {
"options": {
"metadata": {
"metadataValues": [
{
"name": "name",
"value": "={{ $json.name }}"
},
{
"name": "full_text",
"value": "={{ $json.data }}"
}
]
}
},
"jsonData": "={{ $json.text }}",
"jsonMode": "expressionData"
},
"typeVersion": 1
},
{
"id": "a51aa36c-26f0-4d75-a68a-f09405f768e9",
"name": "Merge Ingestion Branches",
"type": "n8n-nodes-base.merge",
"position": [
-1376,
2992
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineByPosition",
"numberInputs": 3
},
"typeVersion": 3.2
},
{
"id": "ef1cc9cb-d519-474c-a64e-90f00e8909e4",
"name": "Summarize Reference Playbooks for Embeddings",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
-1728,
2816
],
"parameters": {
"text": "={{ $json.data }}",
"batching": {},
"messages": {
"messageValues": [
{
"message": "You are a cybersecurity retrieval optimization engine.\n\nYour task is to convert an incident response playbook into a trigger-optimized semantic summary for vector similarity search.\n\nThis summary is not for human readability.\nIt is for maximizing retrieval accuracy.\n\nYour output must:\n\n1. Clearly define the PRIMARY trigger scenario:\n - What exact incident pattern activates this playbook?\n - What detection signals or log patterns indicate it?\n\n2. Explicitly describe distinguishing characteristics:\n - How this scenario differs from related attack types.\n - What makes this playbook unique compared to similar ones.\n\n3. Include:\n - MITRE ATT&CK IDs and tactics.\n - Common detection signals (SIEM, EDR, Cloud logs, IdP logs).\n - Platform scope (AWS, Azure AD, VPN, S3, Email, etc.).\n - Likely attacker behaviors.\n - Alternative terminology and analyst search phrases.\n\n4. Include boundary conditions:\n - When this playbook should NOT be used.\n - Common false positives.\n\n5. Avoid:\n - Step-by-step remediation instructions.\n - Escalation workflow details.\n - Version history.\n - Ownership metadata.\n\n6. Keep output between 300\u2013450 words.\n7. Use dense paragraphs.\n8. Do not use markdown formatting.\n9. End the summary with a compact comma-separated list of retrieval keywords."
}
]
},
"promptType": "define"
},
"retryOnFail": true,
"typeVersion": 1.9
},
{
"id": "c6e5fc5a-63c9-4f36-bc3d-6a449a47e89d",
"name": "Get Test Incidents From GitHub",
"type": "n8n-nodes-base.httpRequest",
"position": [
-656,
3008
],
"parameters": {
"url": "={{ $('Config-Ingestion').item.json.github_baseUrl + '/' + $('Config-Ingestion').item.json.github_repo + '/contents/Test%20Incidents' }}",
"options": {}
},
"executeOnce": true,
"retryOnFail": true,
"typeVersion": 4.4
},
{
"id": "8b803ad3-521d-4a34-9d00-abd7777fa003",
"name": "Download Test Incidents From GitHub",
"type": "n8n-nodes-base.httpRequest",
"position": [
-432,
3008
],
"parameters": {
"url": "={{$json[\"download_url\"]}}",
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
}
},
"retryOnFail": true,
"typeVersion": 4.4
},
{
"id": "5e43ac58-af0e-488b-9a9e-a926e8fcfa50",
"name": "Threat Intel Enrichment Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"onError": "continueErrorOutput",
"position": [
-1824,
4880
],
"parameters": {
"text": "={{ JSON.stringify($json, null, 2) }}",
"options": {
"systemMessage": "# ROLE\nYou are a Real-Time Threat Intelligence & Technical Enrichment Agent.\n\nYou augment incident analysis by performing structured, targeted research using external sources.\nYou do NOT generate the final report. You produce structured research findings for a downstream Synthesizer LLM.\n\n# OBJECTIVE\n\nGiven an incident, determine whether external research is necessary and gather:\n- Active threat intelligence and named campaigns\n- CVE information (exact IDs only \u2014 never invent)\n- Vendor advisories and patch status\n- Exploit availability and active exploitation status\n- Actionable, phase-labeled mitigation guidance\n- Concrete IOCs (hashes, IPs, registry keys, process names) where available\n\nOnly search when it adds value.\n\n# STEP 1 \u2014 CLASSIFY THE INCIDENT TYPE (DO THIS FIRST)\n\nBefore deciding whether to search, classify the incident into one of these types:\n\n| Type | Examples | Search Behavior |\n|---|---|---|\n| SECURITY_ATTACK | exfiltration, ransomware, phishing, credential leak, C2, injection, malware | ALWAYS search |\n| SECURITY_VULNERABILITY | CVE detected, Snyk finding, vulnerable dependency | ALWAYS search \u2014 CVE-first |\n| CLOUD_SECURITY | AWS/Azure/GCP alert, IAM anomaly, S3 access | ALWAYS search |\n| POLICY_VIOLATION | unauthorized software, AUP breach, T1219 | NARROW search only (tooling/uninstall scripts) |\n| AVAILABILITY | memory leak, replication failure, OOM, 500 errors with no exploit evidence | DO NOT search unless MITRE attack technique is present |\n| PERFORMANCE | CPU spike, query slowdown, timeout | DO NOT search |\n\nCRITICAL: A metric spike (HTTP 500 errors, high request rate) is NOT evidence of exploitation unless:\n- A specific CVE pattern is present in the incident data, OR\n- The MITRE technique maps to a known attack (not just error handling), OR\n- A security tool (GuardDuty, EDR, SIEM) has flagged it as malicious\n\nIf in doubt, classify as AVAILABILITY and do NOT search.\n\n# STEP 2 \u2014 SEARCH DECISION RULES\n\n## ALWAYS search when incident type is SECURITY_ATTACK or SECURITY_VULNERABILITY:\n- CVE ID explicitly mentioned in incident data or alert\n- Named threat actor or campaign referenced\n- Active exploitation signals (exfiltration volume, GuardDuty finding, EDR alert)\n- Cloud provider security alert (AWS, Azure, GCP)\n- MITRE ATT&CK technique classified as attack-type (T1059, T1190, T1486, T1530, etc.)\n\n## NARROW search when incident type is POLICY_VIOLATION:\n- Search ONLY for: tool-specific removal commands, network signatures, Group Policy config\n- Do NOT search for threat actors, CVEs, or campaigns\n- Maximum 3 searches\n\n## DO NOT search when:\n- Incident type is AVAILABILITY with no MITRE attack technique\n- Incident type is PERFORMANCE\n- Information is already definitive\n\n## Maximum searches: 10 (3 for POLICY_VIOLATION)\n\n# STEP 3 \u2014 CVE SOURCE HIERARCHY (MANDATORY)\n\nWhen including a CVE card, sources MUST be used in this priority order:\n\n1. MSRC \u2014 `msrc.microsoft.com` (for Microsoft CVEs)\n2. NVD \u2014 `nvd.nist.gov/vuln/detail/CVE-XXXX-XXXXX` (for all CVEs)\n3. Vendor security page \u2014 e.g. `postgresql.org/support/security/`, `apache.org/security/`\n4. CISA KEV \u2014 `cisa.gov/known-exploited-vulnerabilities`\n5. Security research blog \u2014 only if none of the above cover this CVE\n\nA CVE card using a blog as its ONLY source must include `\"applicability_confidence\": \"low\"`.\n\nIf a CVE is NOT explicitly referenced in the incident data:\n- Set `\"applicability_confidence\": \"medium\"` or `\"low\"` with explanation in `applicability_notes`\n- Do NOT set `exploitation_status: \"active\"` unless the CVE is directly correlated to the incident\n\n# STEP 4 \u2014 MITIGATION GUIDANCE RULES\n\n## Phase Labels (REQUIRED on every action)\nEvery action's `phase` field MUST be one of:\n\n- `IMMEDIATE` \u2014 Act within 15 minutes (block, isolate, revoke credentials)\n- `CONTAINMENT` \u2014 Stop the spread (disable shares, quarantine endpoint, network segment)\n- `DETECTION` \u2014 Identify scope (query logs, run forensic commands, check GuardDuty)\n- `INVESTIGATION` \u2014 Determine root cause (Athena queries, heap dumps, git history)\n- `HARDENING` \u2014 Prevent recurrence (policy changes, MFA, patching, WAF rules)\n- `RECOVERY` \u2014 Restore service (promote replica, restore from backup, patch and restart)\n\n## Count Cap: Maximum 6 steps. Prioritize IMMEDIATE and CONTAINMENT first.\n\n## Source Rules:\n- Every step should have a `source_url` where an authoritative source exists.\n- `source_url: null` only for generic first-responder steps with no specific authoritative source.\n- Prefer: official vendor docs > CISA advisories > authoritative security research > vendor blogs\n\n# STEP 5 \u2014 IOC EXTRACTION\n\nExtract concrete, specific IOCs from your research into the `ioc_indicators` array:\n- File hashes (MD5, SHA256)\n- Malicious IP ranges or C2 domain patterns\n- Registry keys used for persistence\n- Specific process names or command strings\n- Port numbers used for C2\n- Ransom note filenames or file extensions\n\nIf no specific IOCs found: set `ioc_indicators: []`\n\n# CRITICAL RULES\n- Zero hallucination: Never invent CVE IDs, version numbers, dates, tool names, threat actor names, or operation names.\n- Date format: Use ISO-8601 `YYYY-MM-DD` or `YYYY-MM` only. Year-only strings like `\"2025\"` are NOT allowed \u2014 use `null` if month is unknown.\n- sources_consulted: Must ONLY list URLs that appear as `source_url` in threat_intelligence or mitigation_guidance. No ghost citations.\n- Category rules:\n - `\"CVE\"` \u2014 only for entries with a real CVE ID (CVE-YYYY-NNNNN format)\n - `\"Active Campaign\"` \u2014 named, documented threat actor operations\n - `\"Vendor Advisory\"` \u2014 official vendor security bulletins\n - `\"Known Issue\"` \u2014 documented vulnerability patterns without CVE\n - `\"Exploit Activity\"` \u2014 documented exploitation methodology\n- active_exploitation_observed: Set `true` only if at least one card has `exploitation_status: \"active\"` AND the threat is directly relevant to the incident type.\n- Source deduplication: Do not include two cards from the same source URL.\n- Keep summaries concise: Max 3 sentences per summary. No narrative paragraphs.\n- Output must be valid JSON matching the provided schema.\n- Evidence priority: Vendor documentation > CISA/NVD > security blogs > forums."
},
"promptType": "define",
"hasOutputParser": true
},
"retryOnFail": true,
"typeVersion": 3.1
},
{
"id": "68606b1b-a948-4304-b238-b790498cc750",
"name": "Search in Tavily",
"type": "@tavily/n8n-nodes-tavily.tavilyTool",
"position": [
-1424,
5136
],
"parameters": {
"query": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Query', ``, 'string') }}",
"options": {}
},
"credentials": {
"tavilyApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "85fcf85d-32d4-4b1c-9bfe-671150345aba",
"name": "Gemini Embeddings (Historical RAG)",
"type": "@n8n/n8n-nodes-langchain.embeddingsGoogleGemini",
"position": [
-1760,
4144
],
"parameters": {
"modelName": "={{ $('Config-Ingestion').item.json.model_embedding }}"
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 1
},
{
"id": "6528e1d6-81d7-49ed-9fea-a189ff6d3967",
"name": "Historical Incidents RAG Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"onError": "continueErrorOutput",
"position": [
-1840,
3824
],
"parameters": {
"text": "=test_incident: {{ JSON.stringify($('Webhook').item.json.body, null, 2) }}",
"options": {
"systemMessage": "You are a Historical Incident Intelligence Agent.\n\nINPUT:\n- test_incident: the raw alert JSON from the current security incident.\n\nTOOL:\n- Use the Supabase Vector Store tool to retrieve similar past resolved incidents via semantic similarity.\n\nDATA FORMAT \u2014 Critical, read before extracting anything:\nEach retrieved result is a single text block of Markdown (pageContent). There is no separate metadata object. All fields must be extracted from the Markdown text by scanning for section headers.\n\nThe Markdown structure is:\n- Header block contains: Incident ID, Severity, Category, Type, Date, Affected Systems\n- ## Alert Source \u2014 contains Detection Tool and Rule/Finding\n- ## Description \u2014 raw alert description\n- ## Detection Gap \u2014 why the alert was not caught sooner (may be absent)\n- ## Root Cause \u2014 root cause analysis text\n- ## What Went Well \u2014 bullet list of positive response actions\n- ## What Went Wrong \u2014 bullet list of response failures\n- ## Resolution Summary \u2014 how the incident was resolved\n- ## Remediation Actions \u2014 bullet list of specific actions taken\n- ## Lessons Learned \u2014 post-incident insight\n- ## MITRE Mapping \u2014 Tactics, Techniques, Prevention IDs\n\nExtraction rules:\n- Parse the incident_id from the line \"**Incident ID:** [value]\" in the header block.\n- Parse severity from \"**Severity:** [value]\", type from \"**Type:** [value]\".\n- For mitre_techniques_used: parse the \"Techniques: [list]\" line under ## MITRE Mapping.\n- For sections that are absent: return null for string fields, [] for array fields.\n\nTASK:\n1. Use the Supabase Vector Store tool to retrieve similar past resolved incidents.\n2. Analyze the retrieved incidents and extract structured historical intelligence.\n\nDo NOT write a triage note.\nDo NOT write a final report.\nDo NOT generate narrative paragraphs.\nYour job is to extract and synthesize patterns from past incidents in structured JSON form only.\n\n---------------------------------\nANALYSIS REQUIREMENTS\n---------------------------------\n\nYou MUST output ONLY valid JSON matching the schema enforced by the output parser. Do not add any explanation text outside the JSON.\n\nIntelligence synthesis rules:\nsimilarity_search_performed: Always true.\n\nmatch_quality:\n \"strong\" \u2192 top result similarity >= 0.80\n \"moderate\" \u2192 top result similarity >= 0.60\n \"weak\" \u2192 top result similarity < 0.60\n \"none\" \u2192 0 results returned\n\nincidents_retrieved: For EACH retrieved incident, extract and return:\n incident_id: parse from \"**Incident ID:** [value]\" in the header block\n similarity_score: similarity float, rounded to 3 decimal places\n incident_type: parse from \"**Type:** [value]\" in the header block\n severity: parse from \"**Severity:** [value]\" in the header block\n resolution_time_minutes: parse from content if mentioned (e.g., \"resolved in 45 minutes\"), else null\n root_cause: 1\u20132 sentence summary from the \"## Root Cause\" section\n resolution_summary: 1\u20132 sentence summary from the \"## Resolution Summary\" section\n key_remediation_actions: top 3 most specific/actionable bullet items from \"## Remediation Actions\"\n lessons_learned: 1 sentence from the \"## Lessons Learned\" section, or null if absent\n mitre_techniques_used: parse the \"Techniques: [T1xxx, T1xxx]\" line under \"## MITRE Mapping\", return as array\n detection_gap: full text from the \"## Detection Gap\" section, or null if that section is absent\n what_went_well: array of bullet items from the \"## What Went Well\" section, or [] if absent\n what_went_wrong: array of bullet items from the \"## What Went Wrong\" section, or [] if absent\n\nhistorical_patterns: Cross-incident synthesis across ALL retrieved incidents:\n most_common_root_cause: the root cause pattern repeating most often (1\u20132 sentences)\n avg_resolution_time_minutes: arithmetic mean of all non-null resolution_time_minutes, or null\n proven_remediation_steps: the 3\u20135 remediation actions appearing most consistently across incidents\n common_mitre_techniques: deduplicated list of all MITRE technique IDs across all retrieved incidents\n recurring_detection_gaps: array \u2014 summarize detection failures that appeared in multiple incidents. Empty array if none found.\n what_went_well_patterns: array \u2014 1\u20132 positive response patterns that historically minimized impact. Empty array if none.\n what_went_wrong_patterns: array \u2014 1\u20132 negative response patterns that historically worsened outcomes. Empty array if none.\n\ncontextual_relevance: How well retrieved incidents match the CURRENT test incident:\n overlap_summary: 1\u20132 sentences on specific overlaps (same type? same MITRE tactic? same affected system?)\n key_differentiators: 1\u20132 sentences on what is DIFFERENT about the test incident vs historical cases\n confidence: \"high\" / \"medium\" / \"low\" \u2014 overall confidence that historical patterns apply to this incident\n\nfallback_note: If 0 results returned, explain that no matches were found and suggest a broader search. If results exist, set to null."
},
"promptType": "define",
"hasOutputParser": true
},
"retryOnFail": true,
"typeVersion": 1.7
},
{
"id": "08ef03eb-41ae-437a-b174-4df59197923c",
"name": "Resolved Incidents Vector Store",
"type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
"position": [
-1760,
4016
],
"parameters": {
"mode": "retrieve-as-tool",
"topK": 3,
"options": {
"queryName": "={{ $('Config-Ingestion').item.json.query_incidents }}"
},
"tableName": {
"__rl": true,
"mode": "id",
"value": "={{ $('Config').item.json.table_resolved }}"
},
"toolDescription": "Search for past incidents using semantic similarity.",
"includeDocumentMetadata": false
},
"credentials": {
"supabaseApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
},
{
"id": "b8dddfdb-3587-48da-83bf-90ee946da31a",
"name": "Playbook Routing Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"maxTries": 2,
"position": [
-1824,
4320
],
"parameters": {
"text": "={{ JSON.stringify($('Code in JavaScript').item.json.body, null, 2) }}",
"options": {
"systemMessage": "You are an Incident Response Playbook Routing Agent.\n\nYour responsibility is to determine whether any retrieved reference playbook is a valid and appropriate match for the current security incident.\n\nPROCESS:\n\nCall the \"Supabase Vector Store\" tool using the incident\u2019s core symptoms, detection signals, affected systems, and MITRE context as your search query.\n\nReview up to 3 retrieved candidate playbooks.\n\nEvaluate whether the playbook\u2019s trigger conditions, attack vector, and operational scope truly match the incident.\n\nMATCHING RULES:\n\nThe attack vector must align (e.g., email phishing, identity brute force, S3 data exfiltration, etc.).\n\nThe scope must align (identity layer vs storage layer vs endpoint).\n\nPrefer the most specific playbook.\n\nDo not select a playbook if the match is weak or generic.\n\nIf uncertain, return no match.\n\nOUTPUT FORMAT (STRICT JSON ONLY). No additional commentary."
},
"promptType": "define",
"hasOutputParser": true
},
"retryOnFail": true,
"typeVersion": 1.7,
"waitBetweenTries": 3000
},
{
"id": "43fba87f-2e66-4a57-8a23-dfb0e41891dc",
"name": "Reference Playbooks Vector Store",
"type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
"position": [
-1648,
4544
],
"parameters": {
"mode": "retrieve-as-tool",
"topK": 3,
"options": {
"queryName": "={{ $('Config-Ingestion').item.json.query_playbooks }}"
},
"tableName": {
"__rl": true,
"mode": "id",
"value": "={{ $('Config').item.json.table_playbooks }}"
},
"toolDescription": "Use this tool to retrieve candidate incident response reference playbooks using semantic similarity against the current incident.\n\nPass a concise description of the incident\u2019s core symptoms, attack vectors, detection signals, and affected systems as the search query.\n\nThe tool returns up to 3 candidate playbooks ranked by similarity. Each result includes:\n\nA semantic summary (content)\nPlaybook uuid and name inside metadata\n\nIMPORTANT: Retrieved playbooks are only candidates. You must evaluate whether their trigger conditions and scope truly match the current incident before selecting one."
},
"credentials": {
"supabaseApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
},
{
"id": "cf9b40e4-9fa4-4fcf-9f94-a4f8ae8df30c",
"name": "Gemini Embeddings (Playbooks)",
"type": "@n8n/n8n-nodes-langchain.embeddingsGoogleGemini",
"position": [
-1776,
4672
],
"parameters": {
"modelName": "={{ $('Config').item.json.model_embedding }}"
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 1
},
{
"id": "64d89692-4547-4320-82ca-3abd3c1ed46a",
"name": "Structured Output Parser - Playbook Router",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
-1360,
4544
],
"parameters": {
"autoFix": true,
"schemaType": "manual",
"inputSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"match_found\": {\n \"type\": \"boolean\",\n \"description\": \"Indicates whether a relevant reference playbook was identified.\"\n },\n \"playbook_id\": {\n \"type\": [\"string\", \"null\"],\n \"description\": \"UUID of the selected playbook. Null if no match.\"\n },\n \"playbook_name\": {\n \"type\": [\"string\", \"null\"],\n \"description\": \"Exact name of the selected playbook. Null if no match.\"\n },\n \"confidence\": {\n \"type\": \"string\",\n \"enum\": [\"high\", \"medium\", \"low\"]\n },\n \"reasoning\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"match_found\",\n \"playbook_id\",\n \"playbook_name\",\n \"confidence\",\n \"reasoning\"\n ],\n \"additionalProperties\": false\n}"
},
"retryOnFail": true,
"typeVersion": 1.3
},
{
"id": "04302602-1d53-4d05-a68c-43df10e28c54",
"name": "Playbook Text Extractor",
"type": "n8n-nodes-base.set",
"position": [
-1136,
4320
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "186d6db5-5244-404d-9ce4-6b51034997f5",
"name": "playbook_text",
"type": "string",
"value": "={{ $('Playbook Routing Agent').item.json.output.match_found ? $json.metadata.full_text : `# Incident Response Playbook: Generic Enterprise Security Incident Response\n\n> **Document Version:** 1.0\n> **Date:** 2026-02-27\n> **Classification:** INTERNAL \u2013 SOC Operations\n> **Review Cycle:** Quarterly\n> **Applies When:** No technique-specific reference playbook is matched for the incident type.\n\n---\n\n## Title & Use Case ID\n\n| Field | Value |\n|---|---|\n| **Playbook Title** | Generic Enterprise Security Incident Response |\n| **Use Case ID** | GEN-UNIVERSAL-001 |\n| **Scope** | All incident categories: Security, Application, Infrastructure, Identity, Availability |\n| **Frameworks** | NIST SP 800-61r2, MITRE ATT&CK Enterprise, CIS Controls v8 |\n| **Version** | 1.0 |\n| **Last Updated** | 2026-02-27 |\n| **Owner** | SOC Manager / Incident Response Lead |\n\n---\n\n## MITRE ATT&CK Mapping\n\n> This playbook is technique-agnostic. Specific MITRE techniques will be identified during triage. Common starting points by incident category:\n\n| Incident Category | Common Tactics | Common Techniques to Investigate |\n|---|---|---|\n| **Identity / Credential** | Initial Access, Credential Access, Persistence | T1078 (Valid Accounts), T1110 (Brute Force), T1098 (Account Manipulation) |\n| **Application / Vulnerability** | Initial Access, Execution | T1190 (Exploit Public-Facing Application), T1059 (Command & Scripting Interpreter) |\n| **Data Exfiltration** | Collection, Exfiltration | T1530 (Data from Cloud Storage), T1020 (Automated Exfiltration) |\n| **Malware / Ransomware** | Execution, Impact | T1486 (Data Encrypted for Impact), T1059 (Command & Scripting Interpreter) |\n| **Insider / Policy Violation** | Collection, Exfiltration | T1039 (Data from Network Shared Drive), T1048 (Exfiltration Over Alt Protocol) |\n| **Infrastructure / Availability** | Impact | T1498 (Network DoS), T1499 (Endpoint DoS) |\n| **Phishing** | Initial Access | T1566 (Phishing), T1078 (Valid Accounts post-compromise) |\n\n> Once the specific technique is confirmed during triage, refer to a technique-specific playbook if one exists.\n\n---\n\n## Objective Statement\n\nThis generic playbook is activated when no technique-specific playbook matches the incoming alert. It provides a **universal incident response lifecycle** applicable to any security, application, infrastructure, or availability incident at an enterprise organisation. The goal is to rapidly determine whether the alert represents malicious activity or a benign anomaly; if malicious, to assess the blast radius, contain the threat, eradicate the root cause, restore systems to normal operation, and capture lessons learned \u2014 all while preserving forensic evidence and meeting SLA obligations.\n\n---\n\n## Alert Analysis\n\n### Alert Triggers (Universal)\n\n- SIEM correlation rule fires on anomalous activity pattern\n- Security tool detection (EDR, XDR, CSPM, WAF, IDS/IPS, DLP) raises alert\n- Automated monitoring detects threshold breach (error rate, authentication failures, traffic spike, data volume anomaly)\n- Threat intelligence platform matches IOC against live traffic or logs\n- User or system administrator reports suspicious behaviour\n- External notification (partner, ISP, law enforcement, bug bounty)\n- Vulnerability scanner or SCA tool identifies a critical finding in production\n\n### Detection Logic / Data Sources\n\n| Data Source | What to Query |\n|---|---|\n| SIEM | Correlated alert details: rule name, triggering events, involved assets and accounts |\n| EDR / XDR | Process trees, file system changes, network connections, lateral movement indicators |\n| Authentication Logs (AD/Entra ID/IdP) | Failed/successful logins, MFA events, account lockouts, session anomalies |\n| Network / Firewall / WAF Logs | Inbound/outbound connections, blocked requests, traffic volume anomalies |\n| Application / Web Logs | HTTP error codes, request volume spikes, API abuse patterns |\n| Cloud Platform Logs (CloudTrail/GCP Audit/Azure Activity) | API calls, configuration changes, IAM activity, resource access |\n| Vulnerability / SCA Scanner Output | CVE identifiers, affected library versions, CVSS scores |\n| DLP / CASB | Data movement alerts, sensitive data access outside normal patterns |\n| Threat Intelligence Platform | IOC lookups: IPs, domains, hashes, CVEs |\n\n---\n\n## Initial Analyst Checklist\n\n> **Note:** Steps marked with \ud83e\udd16 are candidates for SOAR/workflow automation.\n\n- [ ] \ud83e\udd16 **Acknowledge and log the alert** within SLA window; assign incident ticket with severity label\n- [ ] \ud83e\udd16 **Identify the primary affected assets**: hosts, accounts, cloud resources, applications, services\n- [ ] \ud83e\udd16 **Identify the responsible actor(s)**: source IP, user identity, service account, process, or IAM principal\n- [ ] \ud83e\udd16 **Enrich identified IPs and hashes**: query threat intelligence (VirusTotal, AbuseIPDB, GreyNoise) for known malicious indicators\n- [ ] **Determine the earliest known timestamp** of anomalous activity (the \"patient zero\" event)\n- [ ] **Identify the alert type and category**: Security / Application / Infrastructure / Availability / Identity\n- [ ] **Assess initial false-positive likelihood**: Is this activity consistent with a known scheduled job, maintenance window, test activity, or misconfiguration?\n- [ ] **Determine privilege level of involved accounts**: Standard user / Privileged admin / Service account / Shared account\n- [ ] **Identify whether sensitive data is involved**: PII, PHI, financial data, credentials, intellectual property\n- [ ] **Check for lateral movement indicators**: are multiple systems or accounts involved beyond the initial alert?\n- [ ] **Assign severity** per the Severity Classification Matrix below\n- [ ] **Document all findings in the incident ticket** with timestamps, evidence sources, and reasoning\n\n---\n\n## Indicators of Compromise (IOC) Checklist\n\n| IOC Type | Value | Source | Verified? |\n|---|---|---|---|\n| Source IP Address(es) | | Logs / Alerts | \u2610 |\n| Geo-location / ASN of Source IP | | GeoIP / WHOIS | \u2610 |\n| User Account(s) / IAM Principals Involved | | Auth Logs / SIEM | \u2610 |\n| Hostname(s) / Device(s) Affected | | EDR / SIEM | \u2610 |\n| Malware Hash (MD5/SHA256) | | EDR / AV | \u2610 |\n| Malicious Domain / URL | | Web / Proxy Logs | \u2610 |\n| CVE Identifier(s) | | Scanner / External Feed | \u2610 |\n| Anomalous Process Name or Command Line | | EDR | \u2610 |\n| Suspicious File Path or Registry Key | | EDR | \u2610 |\n| Attacked Service / Port / Endpoint | | Firewall / WAF / App Logs | \u2610 |\n| Timeframe of Anomalous Activity | | SIEM | \u2610 |\n| Data Volume Affected (if exfiltration suspected) | | DLP / Network Logs | \u2610 |\n\n---\n\n## Severity Classification Matrix\n\n| Severity | Criteria | Response SLA |\n|---|---|---|\n| **Critical (P1)** | Confirmed compromise of privileged/admin accounts; confirmed data exfiltration of sensitive data; active ransomware or destructive attack; business-critical system unavailable; lateral movement confirmed; regulatory breach threshold likely met | Immediate escalation. Incident bridge within 15 min. |\n| **High (P2)** | Confirmed compromise of standard user account; exploitation of public-facing vulnerability with evidence of code execution; significant service degradation; MFA disabled or bypassed; sensitive data at risk but not confirmed exfiltrated | Escalate to Tier 2 within 15 min. Containment within 1 hour. |\n| **Medium (P3)** | Suspicious activity with no confirmed compromise; policy violation with limited data exposure; single failed exploitation attempt; anomalous access pattern that is not yet confirmed malicious | Triage within 30 min. Investigate and monitor. |\n| **Low (P4)** | Low-fidelity alert; high likelihood of false positive; known benign tool or scanner; no sensitive data involved; single user/system with no escalation indicators | Acknowledge within 1 hour. Verify and close or tune detection rule. |\n\n---\n\n## Triage Steps\n\n1. **Validate the alert is not a false positive**:\n - Does the activity match a known, approved change, maintenance window, or scheduled job?\n - Is the source IP or account associated with an authorised penetration test?\n - Is this a misconfigured service or application generating noise (e.g., stale credentials, expired token)?\n - Cross-reference with the change management system: was anything deployed or modified recently that could explain this behaviour?\n\n2. **Characterise the incident type**:\n - **Security (Attacker-driven)**: malicious external or insider activity \u2014 prioritise containment\n - **Application (Vulnerability/Bug)**: unpatched vulnerability, dependency, or misconfiguration being exploited \u2014 prioritise patch/fix\n - **Infrastructure (Availability)**: system failure, resource exhaustion, or connectivity issue \u2014 prioritise restoration\n - **Identity (Account compromise/misconfiguration)**: credential attack or over-permissive access \u2014 prioritise credential revocation\n\n3. **Determine the blast radius**:\n - How many systems, accounts, or services are affected?\n - Is the impact isolated or expanding?\n - What data classifications are at risk?\n - Is there evidence the attacker has achieved their objective, or are they still active?\n\n4. **Map the MITRE ATT&CK stages** present in the evidence:\n - Initial Access \u2192 Execution \u2192 Persistence \u2192 Privilege Escalation \u2192 Lateral Movement \u2192 Collection \u2192 Exfiltration \u2192 Impact\n - Determine at which stage the attacker is (or was) operating\n\n5. **Assign severity** per the matrix above and escalate accordingly\n\n---\n\n## De-escalated and Expected Benign Events\n\nThe following should be classified as **false positive / benign** and closed after verification:\n\n- **Scheduled automation or batch job**: High-volume API calls, database queries, or file transfers from a known service account during an expected time window. Action: document as baseline event; tune detection threshold.\n- **Authorised change or deployment**: Configuration change, access policy update, or software deployment performed via approved change management. Action: verify ticket reference; close with change ID documented.\n- **Known security scanner or pen test**: Source IP confirmed as authorised internal scanner (Nessus, Snyk, Qualys) or pre-approved penetration test. Action: verify authorisation; add to allowlist; close.\n- **User error / application misconfiguration**: Expired credentials, rotated API keys not yet updated in config, password manager sync issue. Action: assist with remediation; close.\n- **Benign internet scanner (GreyNoise RIOT)**: Source IP is a known harmless research scanner. Action: add to allowlist if recurring; close.\n- **Monitoring or observability tool behaviour**: Legitimate health-check probes, load balancer checks, or synthetic monitoring generating alerts. Action: tune detection to exclude known patterns; close.\n\n---\n\n## Escalation of Incident\n\n### Tier 1 \u2192 Tier 2 Escalation\n**Trigger**: Alert is confirmed as malicious (not false positive) OR severity is P1/P2 OR any of: confirmed system compromise, privileged account involved, sensitive data at risk, lateral movement evidence.\n\n**Actions**:\n- Assign to Tier 2 with full IOC checklist and initial scope assessment\n- Initiate containment steps immediately without waiting for Tier 2 acknowledgement if severity is High+\n- Document handover clearly: what is known, what is unknown, what actions have already been taken\n\n### Tier 2 \u2192 Tier 3 / IR Lead Escalation\n**Trigger**: Confirmed post-compromise activity (data access, privilege escalation, lateral movement, persistence established); business-critical system unavailable; attack is ongoing and spreading; initial containment insufficient.\n\n**Actions**:\n- Page IR Lead and CSIRT (Computer Security Incident Response Team)\n- Open incident bridge / war room\n- Begin forensic preservation of relevant logs (do not alter or delete evidence)\n- Engage relevant SMEs (IAM team, Cloud Security, Network Security, Application Security) per the contacts table below\n- Assess whether law enforcement or regulatory bodies need to be notified\n\n### Tier 3 \u2192 Executive / Legal / Regulatory Escalation\n**Trigger**: Confirmed exfiltration of PII/PHI/regulated data; ransom demand received; business-critical systems unavailable for >2 hours; confirmed state-sponsored or advanced persistent threat activity; regulatory breach notification obligation likely triggered.\n\n**Actions**:\n- Notify CISO within 1 hour\n- Engage Legal / DPO for breach assessment and notification obligations (GDPR, CCPA, HIPAA, etc.)\n- Engage Cyber Insurance carrier\n- Prepare internal and external communications if public-facing impact is possible\n- Consider engaging external forensic firm if internal capability is insufficient\n\n---\n\n## Containment Actions\n\n> **Critical**: Preserve forensic evidence BEFORE destructive containment steps. Capture memory, logs, and disk images from affected systems before isolation or remediation where possible.\n\n### Identity & Access Containment\n- **Disable or lock compromised accounts** immediately upon confirmation of compromise\n- **Revoke all active sessions** for compromised accounts (force sign-out from all devices)\n- **Rotate credentials**: Reset passwords and rotate API keys, tokens, and certificates associated with compromised identities\n- **Revoke MFA devices** for compromised accounts and require re-enrolment through a verified process\n- **Apply temporary deny-all policy** to compromised IAM roles/service principals\n\n### Network Containment\n- **Block malicious IPs/domains** at firewall, WAF, DNS resolver, and proxy levels\n- **Isolate highly affected systems** from the network (VLAN isolation or physical disconnection) if active attacker activity is ongoing\n- **Block outbound connections** on suspicious ports or protocols identified in the investigation\n\n### Application & System Containment\n- **Disable or remove exploited functionality** temporarily (e.g., disable a vulnerable API endpoint, remove a vulnerable plugin)\n- **Enable runtime protection or WAF rules** to block the specific exploit pattern while a patch is prepared\n- **Take snapshots of affected instances** before any remediation (for forensics)\n\n### Data Containment\n- **Restrict access to affected data stores** to read-only or specific approved principals only\n- **Enable additional logging and alerting** on the affected data resource immediately\n\n---\n\n## Eradication & Recovery\n\n1. **Confirm root cause**: Do not proceed to recovery until the root cause is fully understood and documented. Premature recovery without root cause analysis leads to reinfection.\n\n2. **Remove malicious artefacts**: Delete attacker-created accounts, API keys, scheduled tasks, cron jobs, startup items, registry keys, malware files, and any backdoors or persistence mechanisms discovered.\n\n3. **Patch or remediate the exploited vector**:\n - Apply vendor security patches for identified CVEs\n - Update vulnerable libraries or dependencies to non-vulnerable versions\n - Fix the misconfiguration or insecure code that allowed the incident\n\n4. **Rotate all potentially exposed credentials**: Even if not confirmed compromised, rotate credentials for accounts and services that had access to the affected systems during the attack window.\n\n5. **Harden configurations**:\n - Review and apply principle of least privilege to all accounts and services involved\n - Remove unnecessary services, ports, and permissions\n - Validate logging and monitoring coverage is complete before closure\n\n6. **Validate recovery**:\n - Confirm affected systems are stable and operating normally\n - Confirm no reoccurrence of attacker indicators in monitoring\n - Confirm data integrity where data was at risk\n - Obtain sign-off from data/system owner before formal closure\n\n7. **Update detection rules**: Add new IOCs (IPs, hashes, domains, signatures) to SIEM, EDR, and threat intelligence platform watchlists. Tune detection thresholds if alert was noisy.\n\n---\n\n## Automation Opportunities\n\n| Step | Automation Capability | Tool Example |\n|---|---|---|\n| Alert triage and enrichment (IP, hash, domain lookup) | Fully automatable | SOAR + TIP (VirusTotal, GreyNoise, AbuseIPDB) |\n| Asset and identity context enrichment | Fully automatable | SOAR + CMDB / IAM API |\n| IOC blocklist update (firewall, WAF, DNS) | Semi-automatable (approval for P1/P2) | SOAR + Firewall API / DNS RPZ |\n| Account lock / credential revocation | Semi-automatable (approval gate) | SOAR + IdP API |\n| Session revocation | Fully automatable | SOAR + IdP API |\n| Forensic snapshot of affected systems | Fully automatable | SOAR + Cloud Snapshot API / EDR |\n| Ticket creation, enrichment, and escalation routing | Fully automatable | SOAR + ITSM API |\n| Stakeholder notification emails | Fully automatable | SOAR email action |\n| IOC detonation in sandbox | Fully automatable | SOAR + Sandbox API (Any.run, Cuckoo) |\n| Post-patch verification scan | Fully automatable | SOAR + Scanner API (Snyk, Qualys, Nessus) |\n\n---\n\n## Lessons Learned / Post-Incident Review\n\nThe IR Lead should schedule a post-incident review within **5 business days** of closure. Address:\n\n- What was the root cause, and could it have been prevented with existing controls?\n- Were detection thresholds appropriately tuned? Was MTTD (Mean Time to Detect) within target?\n- Was MTTR (Mean Time to Respond) within SLA? If not, where were the delays?\n- Were the right people notified at the right time through the right escalation path?\n- Are there detection gaps that allowed the attacker to operate undetected for a period?\n- Did any forensic evidence get lost due to log retention gaps or destructive containment steps?\n- What automation could reduce manual effort in future similar incidents?\n- Does this incident indicate a systemic issue requiring a broader remediation programme?\n- Should this incident type now have a dedicated technique-specific playbook created?\n\nDocument all findings in the incident ticket. If this incident type is not covered by an existing reference playbook and will recur, assign a task to create one.\n\n---\n\n## Related Frameworks & References\n\n- NIST SP 800-61r2 \u2013 Computer Security Incident Handling Guide\n- NIST SP 800-137 \u2013 Information Security Continuous Monitoring\n- MITRE ATT&CK Enterprise \u2013 https://attack.mitre.org/\n- CIS Controls v8 \u2013 https://www.cisecurity.org/controls/\n- ISO/IEC 27035 \u2013 Information Security Incident Management\n- SANS Incident Handler's Handbook\n\n---\n\n## Revision History\n\n| Version | Date | Author | Changes |\n|---|---|---|---|\n| 1.0 | 2026-02-27 | [Author] | Initial release \u2013 generic fallback playbook |\n` }}"
}
]
}
},
"retryOnFail": true,
"typeVersion": 3.4
},
{
"id": "58ddc17d-af50-4c43-a2d0-1ebfb369e8a4",
"name": "Structured Output Parser - Threat Intel",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
-1776,
5104
],
"parameters": {
"autoFix": true,
"schemaType": "manual",
"inputSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"incident_classification\": {\n \"type\": \"string\",\n \"enum\": [\n \"SECURITY_ATTACK\",\n \"SECURITY_VULNERABILITY\",\n \"CLOUD_SECURITY\",\n \"POLICY_VIOLATION\",\n \"AVAILABILITY\",\n \"PERFORMANCE\"\n ],\n \"description\": \"Incident type classification determined in Step 1. Controls search behavior.\"\n },\n \"external_research_used\": {\n \"type\": \"boolean\",\n \"description\": \"Indicates whether external research was performed.\"\n },\n \"threat_intelligence\": {\n \"type\": \"array\",\n \"maxItems\": 6,\n \"description\": \"Structured findings from CVEs, advisories, campaigns, or known issues. Maximum 6 items.\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"category\": {\n \"type\": \"stri
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
googlePalmApiopenRouterApisupabaseApitavilyApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow ingests incident and playbook content from GitHub into Supabase (including pgvector embeddings with Google Gemini) and, on a webhook trigger, enriches a test incident with historical matches, a routed response playbook, and live web threat intel (via Tavily +…
Source: https://n8n.io/workflows/16446/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Camila IA. Uses postgres, crypto, redis, agent. Webhook trigger; 92 nodes.
Bread-Meat-Delivery. Uses lmChatOpenAi, agent, httpRequest, redis. Webhook trigger; 91 nodes.
My workflow 14. Uses supabase, redis, openAi, googleCalendarTool. Webhook trigger; 91 nodes.
Hi! I’m Amanda, a creator of intelligent automations using n8n and Make. I’ve been building AI-powered workflows for over 2 years, always focused on usability and innovation. This one here is very spe
HeyDinastia. Uses executeCommand, httpRequest, youTube, postgres. Webhook trigger; 66 nodes.