AutomationFlowsAI & RAG › Analyze Vendor Security Risk From Jira Tickets Using Grok, Claude and Slack

Analyze Vendor Security Risk From Jira Tickets Using Grok, Claude and Slack

ByDmitry Uchakin @dmitry-u4 on n8n.io

When a new vendor ticket is created in Jira, this workflow automatically performs a comprehensive security due-diligence investigation and posts the findings back as a Jira comment plus a Slack notification. A Jira webhook fires when an issue is created. An AI agent (Grok)…

Webhook trigger★★★★★ complexityAI-powered37 nodesAgentOpenRouter ChatSlackAgent ToolJira
AI & RAG Trigger: Webhook Nodes: 37 Complexity: ★★★★★ AI nodes: yes Added:
Analyze Vendor Security Risk From Jira Tickets Using Grok, Claude and Slack — n8n workflow card showing Agent, OpenRouter Chat, Slack integration

This workflow corresponds to n8n.io template #15029 — we link there as the canonical source.

This workflow follows the Agent → Agenttool 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 →

Download .json
{
  "id": "loypsWkof4yBWa0v",
  "name": "AI-Powered Vendor Security Risk Analyzer",
  "tags": [],
  "nodes": [
    {
      "id": "7885b6b9-eb0c-4223-94c4-729582119263",
      "name": "Add required fields",
      "type": "n8n-nodes-base.set",
      "position": [
        992,
        2304
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "6060b306-5ddc-4a44-8e4a-7c6ca9b4661b",
              "name": "output.depth",
              "type": "string",
              "value": "=standard"
            },
            {
              "id": "a419cb3e-ddef-4bc7-8c8f-0fa5e82b910e",
              "name": "output.max_sources",
              "type": "string",
              "value": "30"
            },
            {
              "id": "dac1b779-2a27-4a7f-be3e-adeafcf0f61e",
              "name": "output.timeout_seconds",
              "type": "string",
              "value": "900"
            },
            {
              "id": "3ecb48a7-1f18-46ef-9253-073899b95673",
              "name": "output.hints",
              "type": "array",
              "value": "[\"SOC2\", \"privacy policy\"]"
            },
            {
              "id": "31d628d2-6b73-4eba-b6a3-48ed320ae1ef",
              "name": "output.jira_key",
              "type": "string",
              "value": "={{ $('Jira task webhook').item.json.body.issue.key }}"
            },
            {
              "id": "9938bcaf-061a-4013-8a6b-9e7718df32d4",
              "name": "output.effectiveQuery",
              "type": "string",
              "value": "={{\n  (() => {\n    const company = ($json.output.companyName ?? '').toString().trim();\n    const product = ($json.output.productName ?? '').toString().trim();\n\n    if (!company && !product) return '';\n    if (!product) return company;\n\n    if (company.toLowerCase() === product.toLowerCase()) return company;\n    return (company + ' ' + product).trim();\n  })()\n}}"
            },
            {
              "id": "70e59f62-a557-447b-8f78-a4ab2d770f85",
              "name": "output.companyUrl_norm",
              "type": "string",
              "value": "={{   (() => {     const u = ($json.output.companyUrl ?? '').toString().trim();     if (!u) return null;     if (/^https?:\\/\\//i.test(u)) return u;     return 'https://' + u;   })() }}"
            },
            {
              "id": "a418b87b-f726-4c6e-ad2e-a3a13d05e4c3",
              "name": "output.domain",
              "type": "string",
              "value": "={{\n  (() => {\n    const u = (($json.output.companyUrl_norm ?? $json.output.companyUrl) ?? '').toString().trim();\n    if (!u) return null;\n\n    const withScheme = /^https?:\\/\\//i.test(u) ? u : ('https://' + u);\n\n    try {\n      const host = new URL(withScheme).hostname.toLowerCase();\n      return host.replace(/^www\\./, '');\n    } catch (e) {\n      return u\n        .toLowerCase()\n        .replace(/^https?:\\/\\//, '')\n        .replace(/\\/.*$/, '')\n        .replace(/^www\\./, '')\n        .trim() || null;\n    }\n  })()\n}}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "1a7a4121-327b-4053-aaed-428105010316",
      "name": "Extract vendor identity",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        416,
        2304
      ],
      "parameters": {
        "text": "=You are a precise entity extractor for SAAS due-diligence automation. \nAnalyze the incoming JSON payload from Jira webhook and extract exactly three fields: companyName, companyUrl, productName.\n{{ JSON.stringify($json) }}\n\nPriority rules (follow strictly in order):\n1. Find the vendor URL first \u2014 this is the primary source:\n   - Prefer explicit URLs in any field: customfield_*, description, summary, changelog, or body.\n   - Especially look for fields like customfield_12270 (often \"Vendor URL\" or \"Website\").\n   - If URL found (e.g., \"https://www.clay.com/\" or \"clay.com\"), use it as companyUrl.\n   - Normalize: add https:// if missing, strip path/query \u2192 only origin (e.g., https://www.clay.com/ \u2192 https://www.clay.com).\n\n2. companyName:\n   - Derive from companyUrl root domain: \n     - clay.com \u2192 \"Clay\"\n     - upstash.com \u2192 \"Upstash\"\n     - chatgpt.com \u2192 \"ChatGPT\"\n     - acme.com \u2192 \"Acme\"\n   - Remove \"www.\", capitalize properly.\n   - If explicit company name exists in description/summary and differs from domain-derived, prefer explicit only if it's clearly the vendor (e.g., \"OpenAI\" for chatgpt.com).\n   - Do NOT use issue summary as companyName unless no URL found.\n\n3. productName:\n   - Prefer explicit product mention near URL or in summary/description.\n   - If summary = \"Clay\" and URL = \"https://www.clay.com/\", then productName = \"Clay\" (same as company).\n   - If summary = \"ChatGPT Atlas\" and URL = \"https://chatgpt.com/atlas/\", then productName = \"ChatGPT Atlas\".\n   - If path in URL suggests product (e.g., /atlas, /redis), use it only if no better name.\n   - If no distinction, productName can equal companyName.\n\n4. Fallbacks:\n   - If no URL \u2192 try headers.host (e.g., your-instance.app.n8n.cloud \u2192 ignore, not vendor).\n   - If still no URL \u2192 companyUrl = null.\n   - If no clear name \u2192 companyName = null.\n\n5. Output ONLY valid JSON \u2014 no text, no explanations:\n{\n  \"companyName\": string | null,\n  \"companyUrl\": string | null,\n  \"productName\": string | null,\n  \"source\": {\n    \"companyName\": \"brief description or JSON path\",\n    \"companyUrl\": \"brief description or JSON path\",\n    \"productName\": \"brief description or JSON path\"\n  }\n}\n\nExamples:\n- URL: \"https://www.clay.com/\", summary: \"Clay\" \u2192 \n  companyName: \"Clay\", companyUrl: \"https://www.clay.com\", productName: \"Clay\", source: {companyUrl: \"customfield_12270\", ...}\n\n- URL: \"https://chatgpt.com/atlas/\", summary: \"ChatGPT Atlas\" \u2192 \n  companyName: \"ChatGPT\", companyUrl: \"https://chatgpt.com\", productName: \"ChatGPT Atlas\"\n\nNow analyze the provided JSON payload and return the JSON object.",
        "options": {
          "systemMessage": "You are the Orchestrator agent for an evidence-driven security research pipeline. \nYour role: Accept input payload {requestId, companyName, url, depth, max_sources, timeout_seconds, hints (optional), cache_key (optional), productName (optional)}. \n\nNormalize inputs:\n  \u2022 Add https:// to url if missing.\n  \u2022 Generate cache_key = sha256(companyName + url + (productName or \"\")) if not provided.\n  \u2022 Compute effectiveQuery = productName ? \"{{companyName}} {{productName}}\" : \"{{companyName}}\".\n\nCheck cache for fresh results (TTL=7 days; if cached and valid, return it immediately).\n\nDispatch 7 Worker agents in parallel (compliance, data-handling, privacy, security-controls, availability, pricing, company-intel), each with:\n  \u2022 Full payload\n  \u2022 effectiveQuery\n  \u2022 Section-specific instructions\n\nAggregate responses while preserving all evidence:\n  \u2022 Use Chain-of-Thought to detect contradictions (company vs. product vs. third-party).\n  \u2022 Compute confidence per rules.\n  \u2022 Derive data_categories and data_sensitivity (product-aware mapping).\n  \u2022 Flag missing keys in missing_info.\n\nEnforce timeouts by monitoring duration_ms; retry once on transient errors.\nPersist evidence snapshots locally or via cache.\nPrioritize official sources (domain matches url) \u2014 if productName set, prioritize product-specific pages (e.g., plugin docs, GitHub, API portal).\n\nUse deterministic behavior (temperature=0.0).\nOutput ONLY the final JSON matching the schema \u2014 no free text, explanations, or extra keys.\nIf aggregation fails, include error in status field."
        },
        "promptType": "define"
      },
      "typeVersion": 2.2
    },
    {
      "id": "7013b14a-3d9a-4c88-aeae-940fb366aaff",
      "name": "Process values",
      "type": "n8n-nodes-base.set",
      "position": [
        768,
        2304
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "b8a5cbb8-a870-4b8a-adf7-b3e8409db3db",
              "name": "output",
              "type": "object",
              "value": "={{ $json.output }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "ef53a249-680b-4298-8072-4aabd9fac653",
      "name": "Grok 4 Fast (extractor)",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        416,
        2496
      ],
      "parameters": {
        "model": "x-ai/grok-4-fast",
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "4a473584-e9cb-4c37-9cc1-b6bb520747f3",
      "name": "Discover seed URLs",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1328,
        2304
      ],
      "parameters": {
        "text": "=Analyze this vendor:\n- Company Name: {{ $json.output.companyName }}\n- Input URL: {{ $json.output.companyUrl_norm }}\n- Product Name: {{ $json.output.productName }}\n\nINSTRUCTIONS:\n1. Call `perplexity_sub_agent` tool with query: \"[Company Name] official website trust center security compliance\".\n2. Call `perplexity_sub_agent` tool with query: \"site:[Input Domain] OR site:[Company Name] privacy policy terms dpa\".\n3. ANALYZE IDENTITY:\n   - Does the search result redirect to a different domain? (e.g., input `manus.im` -> result `manus.ai`)?\n   - If yes, treat the redirect target as the `primary_domain`.\n4. EXTRACT URLS:\n   - Map found URLs to the output schema.\n   - For 'trust_portal', look for subdomains like `trust.`, `security.`, or paths like `/security`, `/compliance`.",
        "options": {
          "systemMessage": "=ROLE: Seed Discovery & Identity Verification Agent\n\nGOAL:\nYou are the first step in a security due-diligence pipeline. Your job is to:\n1. Identify the \"Official Truth\" domains for the company.\n2. Handle Domain Aliases (e.g., if input is `manus.im` but real site is `manus.ai`, accept the primary).\n3. Return a structured map of URLs for downstream workers.\n\nTOOL USAGE (MANDATORY):\n- You are an OFFLINE model. You MUST use `perplexity_sub_agent` to verify links.\n- Do NOT guess URLs. Only return URLs found via the tool.\n\nOUTPUT RULES (CRITICAL):\n1. **RAW JSON ONLY:** Do NOT use Markdown code blocks (no ```json).\n2. **NO CHATTER:** Do NOT add an \"Analysis Summary\", \"Note\", or any text before/after the JSON.\n3. Start output with `{` and end with `}`.\n\nOUTPUT SCHEMA:\n{\n  \"status\": \"ok\",\n  \"identity\": {\n    \"input_domain\": \"...\",\n    \"primary_domain\": \"...\",\n    \"is_alias\": boolean\n  },\n  \"seed_urls\": {\n    \"trust_portal\": \"url or null\",\n    \"security_page\": \"url or null\",\n    \"privacy_policy\": \"url or null\",\n    \"terms\": \"url or null\",\n    \"subprocessors\": \"url or null\",\n    \"status_page\": \"url or null\"\n  }\n}",
          "returnIntermediateSteps": true
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 3
    },
    {
      "id": "f402317a-7041-4a44-810e-75fb464cc737",
      "name": "Compliance Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        2400,
        1264
      ],
      "parameters": {
        "text": "=TARGET: {{ $('Add required fields').item.json.output.companyName }}\nPRIMARY DOMAIN: {{ $json.output.identity.primary_domain }}\nSEED URLS: {{ JSON.stringify($json.output.seed_urls) }}\n\nTASK:\nUsing the seed URLs (specifically 'trust_portal' and 'security_page') and the `perplexity_sub_agent`:\n1. Find evidence of SOC 2 (Type I or II), ISO 27001, PCI DSS, FedRAMP or any other.\n2. Check the dates. Are the certs current?\n3. If no direct PDF is found, look for a \"Request Access\" page (common for SOC2).\n\nTARGET: {{ $('Add required fields').item.json.output.companyName }}\nPRIMARY DOMAIN: {{ $json.output.identity.primary_domain }}\nSEED URLS: {{ JSON.stringify($json.output.seed_urls) }}\n\nTASK:\n1. **TRUST CENTER DEEP DIVE (Priority 1):**\n   - If a 'trust_portal' URL is provided (e.g., trust.manus.im), you MUST analyze it specifically.\n   - Trust Centers often host \"Subprocessors\", \"Security Controls\", and \"Report Request\" buttons.\n   - Search specifically for: `site:{{ $json.output.seed_urls.trust_portal }} \"SOC 2\" OR \"ISO 27001\" OR \"controls\" OR \"subprocessors\"`\n   - If the main trust page seems empty, look for sub-pages like `/compliance`, `/security`, `/legal`.\n\n2. **CERTIFICATION VERIFICATION:**\n   - Find evidence of SOC 2 (Type I or II), ISO 27001, PCI DSS, or FedRAMP.\n   - **Crucial:** Distinguish between \"We are SOC 2 Compliant\" (marketing claim) vs \"Download SOC 2 Report\" (evidence).\n   - Check dates: Evidence older than 18 months is \"Outdated\".\n\n3. **GAPS:**\n   - If you found the Trust Center but cannot see the *content* of the reports (e.g., locked behind login), Report \"Status: Gated/Requestable\" rather than \"Missing\".",
        "options": {
          "maxIterations": 20,
          "systemMessage": "ROLE: Compliance Research Specialist\nGOAL: Verify formal security attestations (SOC 2, ISO, PCI, FedRAMP).\n\n## TOOL USAGE (MANDATORY)\n- You are an OFFLINE model. You MUST use `perplexity_sub_agent`.\n- You MUST perform a specific \"Deep Dive\" search if a Trust Portal URL is provided.\n\n## OUTPUT RULES\n1. **RAW JSON ONLY:** No Markdown, no chatter.\n2. **STATUS DEFINITIONS:**\n   - \"Present\": Found direct evidence (PDF, badge, text).\n   - \"Gated\": Found a \"Request Report\" or \"NDA\" page.\n   - \"Missing\": No evidence found after searching.\n3. **EVIDENCE:** Include exact URLs and concise snippets.\n\nOUTPUT SCHEMA:\n{\n  \"agent\": \"Compliance Agent\",\n  \"key_findings\": [\n    {\n      \"topic\": \"SOC 2|ISO 27001|PCI DSS|FedRAMP|HIPAA\",\n      \"status\": \"Present|Missing|Gated|Outdated\",\n      \"summary\": \"e.g. 'SOC 2 Type II report covering 2024-2025 available via Trust Portal.'\",\n      \"url\": \"...\"\n    }\n  ],\n  \"evidence\": [ { \"url\": \"...\", \"snippet\": \"...\", \"source_type\": \"official|third_party\" } ]\n}"
        },
        "promptType": "define"
      },
      "typeVersion": 3
    },
    {
      "id": "532f2d05-49c1-41a8-90b2-d57d4febe0d2",
      "name": "Data Handling Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        2400,
        1424
      ],
      "parameters": {
        "text": "=TARGET: {{ $('Add required fields').item.json.output.companyName }}\nPRIMARY DOMAIN: {{ $json.output.identity.primary_domain }}\nSEED URLS: {{ JSON.stringify($json.output.seed_urls) }}\n\nTASK:\n1. **SUBPROCESSORS:**\n   - Search: `site:{{ $json.output.identity.primary_domain }} \"subprocessors\" OR \"sub-processors\" OR \"third party vendors\"`\n   - Summary: Do they have a public list?\n\n2. **DPA & RESIDENCY:**\n   - Search: `site:{{ $json.output.identity.primary_domain }} \"Data Processing Agreement\" OR \"DPA\" OR \"EU hosting\" OR \"data residency\"`\n   - Summary: Can customers choose EU vs US storage? Is there a standard DPA?\n\n3. **RETENTION:**\n   - Search: `site:{{ $json.output.identity.primary_domain }} \"data retention\" OR \"deletion policy\" OR \"termination\"`\n   - Summary: What happens to data after the contract ends? (e.g., deleted in 30 days).",
        "options": {
          "maxIterations": 20,
          "systemMessage": "ROLE: Data Governance Specialist\nGOAL: Map data processing, residency, subprocessors, and retention policies.\n\n## TOOL USAGE (MANDATORY)\n- You are an OFFLINE model. Use `perplexity_sub_agent`.\n\n## OUTPUT RULES\n1. **RAW JSON ONLY:** No Markdown.\n2. **PRIORITY:** Focus on finding the actual DPA PDF or page.\n\nOUTPUT SCHEMA:\n{\n  \"agent\": \"Data Handling Agent\",\n  \"key_findings\": [\n    {\n      \"topic\": \"DPA|Subprocessors|Data Residency|Retention\",\n      \"status\": \"Present|Missing|Unclear\",\n      \"summary\": \"...\",\n      \"url\": \"...\"\n    }\n  ],\n  \"evidence\": [ { \"url\": \"...\", \"snippet\": \"...\", \"source_type\": \"official|third_party\" } ]\n}"
        },
        "promptType": "define"
      },
      "typeVersion": 3
    },
    {
      "id": "dffdda53-e4ef-47e3-b7ec-0558340ea580",
      "name": "Privacy & Legal Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        2400,
        1616
      ],
      "parameters": {
        "text": "=TARGET: {{ $('Add required fields').item.json.output.companyName }}\nPRIMARY DOMAIN: {{ $json.output.identity.primary_domain }}\nSEED URLS: {{ JSON.stringify($json.output.seed_urls) }}\n\nTASK:\n1. **FRAMEWORKS:**\n   - Search: `site:{{ $json.output.identity.primary_domain }} \"GDPR\" OR \"CCPA\" OR \"CPRA\"`\n   - Search: `site:{{ $json.output.identity.primary_domain }}\"Data Privacy Framework\" OR \"Standard Contractual Clauses\" OR \"SCC\"`\n\n2. **USER RIGHTS:**\n   - Check the Privacy Policy URL provided.\n   - Summary: Do they list specific rights (Right to be Forgotten, Access)? Is there a `privacy@` email?",
        "options": {
          "maxIterations": 20,
          "systemMessage": "ROLE: Privacy Legal Analyst\nGOAL: Assess alignment with GDPR, CCPA, and International Data Transfers.\n\n## TOOL USAGE (MANDATORY)\n- You are an OFFLINE model. Use `perplexity_sub_agent`.\n\n## OUTPUT RULES\n1. **RAW JSON ONLY:** No Markdown.\n2. **SPECIFICITY:** Do not just say \"They comply with laws\". Quote the specific frameworks (GDPR, CCPA, DPF).\n\nOUTPUT SCHEMA:\n{\n  \"agent\": \"Privacy Agent\",\n  \"key_findings\": [\n    {\n      \"topic\": \"GDPR|CCPA|Transfers|Rights\",\n      \"status\": \"Explicit|Implied|Missing\",\n      \"summary\": \"...\",\n      \"url\": \"...\"\n    }\n  ],\n  \"evidence\": [ { \"url\": \"...\", \"snippet\": \"...\", \"source_type\": \"official|third_party\" } ]\n}"
        },
        "promptType": "define"
      },
      "typeVersion": 3
    },
    {
      "id": "a234a10b-4597-4f5d-9ea5-4e5e4108241f",
      "name": "Security Controls Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        2400,
        1808
      ],
      "parameters": {
        "text": "=TARGET: {{ $('Add required fields').item.json.output.companyName }}\nPRIMARY DOMAIN: {{ $json.output.identity.primary_domain }}\nSEED URLS: {{ JSON.stringify($json.output.seed_urls) }}\n\nTASK:\n1. **AUTHENTICATION:**\n   - Search: `site:{{ $json.output.identity.primary_domain }} \"SSO\" OR \"SAML\" OR \"SCIM\" OR \"Single Sign On\"`\n   - Search: `site:{{ $json.output.identity.primary_domain }} \"MFA\" OR \"2FA\" OR \"Multi-factor\"`\n\n2. **RED TEAM / INCIDENT HISTORY (CRITICAL):**\n   - Search: `\"{{ $('Process values').item.json.output.companyName }}\" data breach OR security incident OR ransomware OR hacked`\n   - Search: `\"{{ $('Process values').item.json.output.companyName }}\" CVE vulnerabilities exploit`\n   - Search: `site:reddit.com \"{{ $('Process values').item.json.output.companyName }}\" security concern`\n\n3. **VULNERABILITY DISCLOSURE:**\n   - Search: `site:{{ $json.output.identity.primary_domain }} \"security.txt\" OR \"bug bounty\" OR \"responsible disclosure\"`\n   - Search: `\"{{ $('Process values').item.json.output.companyName }}\" bug bounty program`\n",
        "options": {
          "maxIterations": 20,
          "systemMessage": "ROLE: Technical Security Analyst\nGOAL: Validate existence of SSO, MFA, RBAC, and Vulnerability Disclosure.\n\n## TOOL USAGE (MANDATORY)\n- You are an OFFLINE model. Use `perplexity_sub_agent`.\n\n## OUTPUT RULES\n1. **RAW JSON ONLY:** No Markdown.\n2. **FOCUS:** Differentiate between \"Internal security\" (what they do) and \"Customer features\" (SSO/MFA for users). Focus on Customer Features.\n\nOUTPUT SCHEMA:\n{\n  \"agent\": \"Security Controls Agent\",\n  \"key_findings\": [\n    {\n      \"topic\": \"SSO|MFA|RBAC|VDP\",\n      \"status\": \"Supported|Not Found|Add-on\",\n      \"summary\": \"e.g. 'SAML SSO supported via Okta/OneLogin'\",\n      \"url\": \"...\"\n    }\n  ],\n  \"evidence\": [ { \"url\": \"...\", \"snippet\": \"...\", \"source_type\": \"official|third_party\" } ]\n}"
        },
        "promptType": "define"
      },
      "typeVersion": 3
    },
    {
      "id": "9fb288fb-85e1-4052-9789-94809cf39b31",
      "name": "Availability Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        2400,
        2016
      ],
      "parameters": {
        "text": "=TARGET: {{ $('Add required fields').item.json.output.companyName }}\nPRIMARY DOMAIN: {{ $json.output.identity.primary_domain }}\nSEED URLS: {{ JSON.stringify($json.output.seed_urls) }}\n\nTASK:\n1. **STATUS PAGE:**\n   - If a status URL exists, check it. Does it show historical uptime?\n   - If not, search: `site:{{ $json.output.identity.primary_domain }} \"status\" OR \"uptime\"`\n   - Search broad: `\"{{ $('Process values').item.json.output.companyName }}\" status page`\n\n2. **SLA & DR:**\n   - Search: `site:{{ $json.output.identity.primary_domain }} \"SLA\" OR \"Service Level Agreement\" OR \"uptime guarantee\"`\n   - Search: `site:{{ $json.output.identity.primary_domain }}\"disaster recovery\" OR \"RTO\" OR \"RPO\"`",
        "options": {
          "maxIterations": 20,
          "systemMessage": "ROLE: Site Reliability Analyst\nGOAL: Confirm uptime transparency, Status Pages, and SLA terms.\n\n## TOOL USAGE (MANDATORY)\n- You are an OFFLINE model. Use `perplexity_sub_agent`.\n\n## OUTPUT RULES\n1. **RAW JSON ONLY:** No Markdown.\n\nOUTPUT SCHEMA:\n{\n  \"agent\": \"Availability Agent\",\n  \"key_findings\": [\n    {\n      \"topic\": \"Status Page|SLA|Disaster Recovery\",\n      \"status\": \"Public|Private|Missing\",\n      \"summary\": \"...\",\n      \"url\": \"...\"\n    }\n  ],\n  \"evidence\": [ { \"url\": \"...\", \"snippet\": \"...\", \"source_type\": \"official|third_party\" } ]\n}"
        },
        "promptType": "define"
      },
      "typeVersion": 3
    },
    {
      "id": "0044fad7-5069-46b0-afe5-68351726b27c",
      "name": "Pricing Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        2400,
        2224
      ],
      "parameters": {
        "text": "=TARGET: {{ $('Add required fields').item.json.output.companyName }}\nPRIMARY DOMAIN: {{ $json.output.identity.primary_domain }}\n\nTASK:\n1. **TIERS & SSO TAX:**\n   - Search: `site:{{ $json.output.identity.primary_domain }}pricing`\n   - Search: `site:{{ $json.output.identity.primary_domain }}\"enterprise plan\" features`\n   - **Specific Goal:** Does the \"Pro\" or \"Team\" plan include SSO/SAML? Or is it Enterprise only?\n\n2. **COMMERCIAL TERMS:**\n   - Search: `site:{{ $json.output.identity.primary_domain }}\"refund policy\" OR \"cancellation\" OR \"money back\"`",
        "options": {
          "maxIterations": 20,
          "systemMessage": "ROLE: Procurement Analyst & JSON API\nGOAL: Extract commercial terms, pricing tiers, and \"SSO Tax\" risks.\n\n## TOOL USAGE (MANDATORY)\n- You are an OFFLINE model. Use `perplexity_sub_agent`.\n\n## OUTPUT RULES (CRITICAL)\n1. **YOU ARE AN API.** Do not speak plain English. Do not write summaries.\n2. **RAW JSON ONLY.** No Markdown fences. Start with `{` and end with `}`.\n3. If SSO costs extra (e.g., \"Enterprise only\" or \"Flat fee\"), mark \"SSO Tax\" as \"Verified\".\n\nOUTPUT SCHEMA:\n{\n  \"agent\": \"Pricing Agent\",\n  \"key_findings\": [\n    {\n      \"topic\": \"Pricing Structure|SSO Tax|Refunds\",\n      \"status\": \"Verified|Unclear\",\n      \"summary\": \"Brief factual sentence.\",\n      \"url\": \"...\"\n    }\n  ],\n  \"evidence\": [ { \"url\": \"...\", \"snippet\": \"...\", \"source_type\": \"official|third_party\" } ]\n}"
        },
        "promptType": "define"
      },
      "typeVersion": 3
    },
    {
      "id": "e9405ad0-df40-4fd5-876e-0f7e3d0227fb",
      "name": "Company Intel Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        2400,
        2448
      ],
      "parameters": {
        "text": "=TARGET: {{ $('Add required fields').item.json.output.companyName }}\nPRIMARY DOMAIN: {{ $json.output.identity.primary_domain }}\n\nTASK:\n1. **CORPORATE IDENTITY:**\n   - Search: `\"{{ $('Process values').item.json.output.companyName }}\" legal entity name headquarters`\n   - Search: `\"{{ $('Process values').item.json.output.companyName }}\" funding crunchbase linkedin`\n\n2. **VERIFY:**\n   - Official Legal Name (e.g., \"Manus AI, Inc.\").\n   - Headquarters Country/City.\n   - Funding stage (Seed, Series A, Public, Acquired?).\n   - Year Founded.",
        "options": {
          "maxIterations": 20,
          "systemMessage": "ROLE: Corporate Intelligence Analyst\nGOAL: Verify Legal Entity, HQ, Funding, and Acquisition status.\n\n## TOOL USAGE (MANDATORY)\n- You are an OFFLINE model. Use `perplexity_sub_agent`.\n\n## OUTPUT RULES\n1. **RAW JSON ONLY:** No Markdown.\n\nOUTPUT SCHEMA:\n{\n  \"agent\": \"Company Intel Agent\",\n  \"key_findings\": [\n    {\n      \"topic\": \"Legal Entity|HQ|Funding|Founded\",\n      \"status\": \"Verified|Unknown\",\n      \"summary\": \"...\",\n      \"url\": \"...\"\n    }\n  ],\n  \"evidence\": [ { \"url\": \"...\", \"snippet\": \"...\", \"source_type\": \"official|third_party\" } ]\n}"
        },
        "promptType": "define"
      },
      "typeVersion": 3
    },
    {
      "id": "8fd84ede-806d-4f32-83c3-d7ac0a6e721e",
      "name": "Aggregate",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        3776,
        1936
      ],
      "parameters": {
        "options": {
          "mergeLists": true
        },
        "fieldsToAggregate": {
          "fieldToAggregate": [
            {
              "fieldToAggregate": "output"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "2f5034a6-03df-4852-b0b2-4c85435dff23",
      "name": "Lead Security Analyst",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        4064,
        1936
      ],
      "parameters": {
        "text": "=Here are the structured findings from the research team:\n{{ JSON.stringify($('Aggregate').item.json.output) }}\n\nJira Key: {{ $('Jira task webhook').item.json.body.issue.key }}\nJira Browser URL: https://YOUR-JIRA-DOMAIN.atlassian.net/browse/{{ $('Jira task webhook').item.json.body.issue.key }}\n\nTASK:\n1. Deduplicate the \"evidence\" across all agents.\n2. Generate the Jira Wiki Markup body.\n3. Generate the Slack Block Kit JSON (including the \"Actions\" button).",
        "options": {
          "systemMessage": "ROLE: Lead Security Analyst (Aggregator)\nGOAL: Synthesize 7 research streams into a unified Vendor Security Report for Jira and Slack.\n\nINPUT DATA:\n- Research results from 7 agents.\n- Jira Key and URL.\n\nINSTRUCTIONS:\n1. **Consolidate Evidence:**\n   - Merge duplicate URLs.\n   - Assign global IDs (E1, E2...).\n   - Reference IDs in findings.\n\n2. **Assess Risk:**\n   - HIGH: Missing SOC2/ISO, No DPA, No SSO, HIPAA violations.\n   - MED: No Status Page, Missing Subprocessor list.\n\n3. **Generate Output JSON:**\n   - `jira_body`: Jira Wiki Markup (h1, h2, tables).\n   - `slack_blocks`: Native JSON array.\n     - Block 1: Header (\"Vendor Security Report: <Vendor>\")\n     - Block 2: Section (Context/Overview)\n     - Block 3: Section (Highlights - Top 3 Pros)\n     - Block 4: Section (Risks - Top 3 Gaps)\n     - Block 5: Actions (Button: \"View Report in Jira\", URL: <Jira Browser URL>)\n\nOUTPUT JSON SCHEMA:\n{\n  \"jira_body\": \"string (wiki markup)\",\n  \"slack_blocks\": [\n    { \"type\": \"header\", \"...\":\"...\" },\n    { \"type\": \"section\", \"...\":\"...\" },\n    { \"type\": \"actions\", \"elements\": [ { \"type\": \"button\", \"text\": {\"...\":\"...\"}, \"url\": \"...\" } ] }\n  ],\n  \"slack_text\": \"Short summary for notification\"\n}",
          "returnIntermediateSteps": false
        },
        "promptType": "define"
      },
      "typeVersion": 3
    },
    {
      "id": "11daaab5-350f-4a41-bcd7-fafc58faf50e",
      "name": "Post to Slack channel",
      "type": "n8n-nodes-base.slack",
      "position": [
        4832,
        1936
      ],
      "parameters": {
        "select": "channel",
        "blocksUi": "={\n  \"attachments\": [\n    {\n      \"color\": \"{{ $json.colorBar || '#D70000' }}\",\n      \"blocks\": {{ JSON.stringify($('Unwrap final report').item.json.output.slack_blocks) }}\n    }\n  ]\n}",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": ""
        },
        "messageType": "block",
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "1626ba6b-a91a-4341-9680-46cae20f2f4e",
      "name": "perplexity_sub_agent",
      "type": "@n8n/n8n-nodes-langchain.agentTool",
      "position": [
        2688,
        2784
      ],
      "parameters": {
        "text": "=Research the following query passed by the lead agent:\n\"{{ $fromAI('query') }}\"\n\nCONSTRAINTS:\n1. Max Results: {{ $fromAI('max_sources') || 6 }}\n2. Format: Return STRICT JSON only.\n3. Content: Focus on extracting facts, dates, and snippets.",
        "options": {
          "systemMessage": "=ROLE: Web Search & Extraction Sub-Agent\n\nGOAL:\nYou are an interface to the real-time web. You receive a specific `query` from a Lead Researcher and must return factual results in JSON format.\n\nINPUT HANDLING:\n- You will receive a query variable. You MUST run a live web search for it.\n- If the query contains `site:`, strictly filter results to that domain.\n\nOUTPUT RULES (STRICT JSON):\n1. Do NOT chat. Do NOT use Markdown (```json). Just return the raw JSON object.\n2. Structure:\n{\n  \"results\": [\n    {\n      \"title\": \"Page Title\",\n      \"url\": \"Full URL\",\n      \"date\": \"YYYY-MM-DD\" or null,\n      \"snippet\": \"The specific text relevant to the query.\",\n      \"source_type\": \"first_party (if matches site: operator) | third_party (reviews/news)\"\n    }\n  ]\n}\n\n3. SNIPPET QUALITY:\n   - If the query asks for \"SOC 2\", the snippet MUST contain the text regarding SOC 2.\n   - Do not return generic homepage descriptions.\n\nERROR HANDLING:\n- If no results found, return { \"results\": [] }."
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "d165c192-ce2a-4316-8550-55b1991d07eb",
      "name": "Parse discovery JSON",
      "type": "n8n-nodes-base.code",
      "position": [
        1680,
        2304
      ],
      "parameters": {
        "jsCode": "// Clean up markdown/text from the AI output\nconst raw = items[0].json.output;\nlet clean = raw;\n\n// Remove markdown fences\nif (typeof raw === 'string') {\n  clean = raw.replace(/```json/g, '').replace(/```/g, '');\n  \n  // Extract just the JSON object (find first { and last })\n  const firstOpen = clean.indexOf('{');\n  const lastClose = clean.lastIndexOf('}');\n  if (firstOpen !== -1 && lastClose !== -1) {\n    clean = clean.substring(firstOpen, lastClose + 1);\n  }\n  \n  try {\n    return [{ json: { output: JSON.parse(clean) } }];\n  } catch (e) {\n    // If parse fails, return raw to debug\n    return [{ json: { output: raw, error: \"Parse Failed\" } }];\n  }\n}\n\nreturn items;"
      },
      "typeVersion": 2
    },
    {
      "id": "dc9deb61-41f5-4eca-87aa-3b6269f6f245",
      "name": "Section 1 \u2014 Ingestion Pipeline",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        1888
      ],
      "parameters": {
        "width": 1152,
        "height": 784,
        "content": "## 1. Ingestion Pipeline\n\nReceive the Jira webhook and normalize the vendor target (company, URL, product) into a clean payload for downstream agents."
      },
      "typeVersion": 1
    },
    {
      "id": "94b1df9e-d5df-4848-9b82-bbe91269b1c2",
      "name": "Section 2 \u2014 Discovery Engine",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1248,
        1872
      ],
      "parameters": {
        "width": 816,
        "height": 800,
        "content": "## 2. Discovery Engine\n\nResolve the vendor's canonical URLs (Trust Center, Privacy Policy, Subprocessors, Status page) before deep research. Prevents downstream agents from hallucinating URLs."
      },
      "typeVersion": 1
    },
    {
      "id": "9a94618b-4dd0-4f88-8159-3ec0f4b4e16b",
      "name": "Claude Sonnet 4.5 (discovery)",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        1328,
        2496
      ],
      "parameters": {
        "model": "anthropic/claude-sonnet-4.5",
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "6d58ea4a-1dff-413a-a650-a4a8de9dfa68",
      "name": "Unwrap discovery payload",
      "type": "n8n-nodes-base.set",
      "position": [
        1888,
        2304
      ],
      "parameters": {
        "options": {
          "ignoreConversionErrors": true
        },
        "assignments": {
          "assignments": [
            {
              "id": "924c17f8-d026-480b-9553-72f927160e94",
              "name": "output",
              "type": "object",
              "value": "={{ $json.output }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "afc9b175-bcd7-4eda-9f0e-1e50da88d44d",
      "name": "Section 3 \u2014 Parallel Research Swarm",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2096,
        1024
      ],
      "parameters": {
        "width": 928,
        "height": 2048,
        "content": "## 3. Parallel Research Swarm\n\nSeven specialist agents run concurrently \u2014 Compliance, Data Handling, Privacy & Legal, Security Controls, Availability, Pricing, Company Intel \u2014 each with a focused JSON output schema. All share one `perplexity_sub_agent` tool for live web search and the same Claude Sonnet 4.5 brain."
      },
      "typeVersion": 1
    },
    {
      "id": "9d85fa50-f97a-424e-bae6-ef430b7d7eaa",
      "name": "Claude Sonnet 4.5 (workers)",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        2144,
        2560
      ],
      "parameters": {
        "model": "anthropic/claude-sonnet-4.5",
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "467bd8f0-b129-4939-ad86-2056d8729714",
      "name": "Section 4 \u2014 Synthesis Pipeline",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3088,
        1504
      ],
      "parameters": {
        "width": 864,
        "height": 720,
        "content": "## 4. Synthesis Pipeline\n\nCollapse the 7 asynchronous JSON streams into one clean evidence set: merge \u2192 sanitize (strip markdown fences, handle bad JSON) \u2192 unwrap \u2192 aggregate all `key_findings[]` and `evidence[]` arrays for the Lead Analyst."
      },
      "typeVersion": 1
    },
    {
      "id": "88f838db-401d-488a-b713-bd1b0d9a27c0",
      "name": "Comment on Jira ticket",
      "type": "n8n-nodes-base.jira",
      "position": [
        4624,
        1936
      ],
      "parameters": {
        "comment": "={{ $json.output.jira_body }}",
        "options": {
          "wikiMarkup": true
        },
        "issueKey": "={{ $('Jira task webhook').item.json.body.issue.key }}",
        "resource": "issueComment"
      },
      "credentials": {
        "jiraSoftwareCloudApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "eaefa639-909d-46bf-866a-61d86cfd0506",
      "name": "Unwrap final report",
      "type": "n8n-nodes-base.set",
      "position": [
        4416,
        1936
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "becc0407-52ad-47eb-bbc0-14501ccd1919",
              "name": "output",
              "type": "object",
              "value": "={{ $json.output }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "2742011c-bffb-4799-aeff-57cd59120f94",
      "name": "Section 5 \u2014 Reporting Layer",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4000,
        1504
      ],
      "parameters": {
        "width": 1072,
        "height": 720,
        "content": "## 5. Reporting Layer\n\nLead Analyst deduplicates evidence, scores risk (High / Med / Low), and produces both Jira Wiki Markup and Slack Block Kit outputs \u2014 posted to the original ticket and to your security channel."
      },
      "typeVersion": 1
    },
    {
      "id": "d57ec509-f95c-42d4-bd2f-731ec6fbec19",
      "name": "Grok 4 Fast (synthesizer)",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        4064,
        2080
      ],
      "parameters": {
        "model": "x-ai/grok-4-fast",
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "069c4ae8-253c-4878-a076-59cb64142f1b",
      "name": "Perplexity Sonar Pro (search)",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "onError": "continueRegularOutput",
      "maxTries": 5,
      "position": [
        2544,
        2912
      ],
      "parameters": {
        "model": "perplexity/sonar-pro-search",
        "options": {}
      },
      "retryOnFail": true,
      "typeVersion": 1,
      "waitBetweenTries": 5000
    },
    {
      "id": "7bbdb7da-9548-4c3e-95fb-8c0967d574b1",
      "name": "Merge agent outputs",
      "type": "n8n-nodes-base.merge",
      "position": [
        3184,
        1856
      ],
      "parameters": {
        "numberInputs": 7
      },
      "typeVersion": 3.2
    },
    {
      "id": "ca8a6529-ff37-4e3b-bb3e-eb0a3a76bc2a",
      "name": "Sanitize agent JSON",
      "type": "n8n-nodes-base.code",
      "position": [
        3392,
        1936
      ],
      "parameters": {
        "jsCode": "// Loop over all 7 agent results\nconst results = items.map(item => {\n  let raw = item.json.output;\n  \n  if (typeof raw === 'string') {\n    let clean = raw.replace(/```json/g, '').replace(/```/g, '').trim();\n    const firstCurly = clean.indexOf('{');\n    const lastCurly = clean.lastIndexOf('}');\n    if (firstCurly !== -1 && lastCurly !== -1) {\n      clean = clean.substring(firstCurly, lastCurly + 1);\n    }\n    try {\n      return { json: { output: JSON.parse(clean) } };\n    } catch (e) {\n      return { json: { output: { agent: \"Error Parsing Agent\", error: \"Agent returned invalid JSON\", raw_content: raw } } };\n    }\n  }\n  return item;\n});\n\nreturn results;"
      },
      "typeVersion": 2
    },
    {
      "id": "9d8e1237-a287-426d-ba02-a3d2660e012f",
      "name": "Unwrap synthesis payload",
      "type": "n8n-nodes-base.set",
      "position": [
        3568,
        1936
      ],
      "parameters": {
        "options": {
          "ignoreConversionErrors": true
        },
        "assignments": {
          "assignments": [
            {
              "id": "924c17f8-d026-480b-9553-72f927160e94",
              "name": "output",
              "type": "object",
              "value": "={{ $json.output }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "5e2cf78c-58a9-4266-bc29-10da8c5df12a",
      "name": "Jira task webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        48,
        2304
      ],
      "parameters": {
        "path": "ai-vendor-security-analyzer",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2.1
    },
    {
      "id": "2d1e54a5-710c-4abf-bffb-034ac838cb56",
      "name": "Workflow Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "parameters": {
        "color": 3,
        "width": 1600,
        "height": 880,
        "content": "## \ud83d\udd10 AI-Powered Vendor Security Risk Analyzer\n\n### Who's it for\nSecurity teams, procurement, and compliance leads running third-party SaaS vendor risk assessments. If you currently spend an hour per vendor digging through Trust Centers, privacy pages, and sub-processor lists, this workflow condenses that work into ~90 seconds of automated, evidence-linked research.\n\n### What it does\nWhen a security-review ticket is opened in Jira, seven specialist research agents run in parallel across the vendor's official sources. A Lead Analyst scores the risk (High / Med / Low) and posts a consolidated report back to the Jira ticket and to a Slack channel \u2014 with direct links to every piece of evidence.\n\n### How it works\n1. **Ingest** \u2014 Jira webhook fires on ticket creation; an extractor agent parses the payload to pull the vendor's name, URL, and product.\n2. **Discover** \u2014 A Seed URL Discovery Agent resolves the canonical Trust Center, Privacy Policy, Subprocessors page and Status page. Handles domain aliases (e.g. `manus.im` \u2192 `manus.ai`).\n3. **Research (fan-out)** \u2014 Seven specialist agents run concurrently: Compliance, Data Handling, Privacy & Legal, Security Controls, Availability, Pricing, Company Intel. All share one Perplexity sub-agent for live web search.\n4. **Synthesize (fan-in)** \u2014 Merge \u2192 sanitize JSON \u2192 deduplicate evidence \u2192 aggregate into a single payload for the Lead Analyst.\n5. **Report** \u2014 Lead Analyst scores risk, formats Jira Wiki Markup + Slack Block Kit, and posts to both channels.\n\n### How to use\n1. Add three credentials: **OpenRouter** (API key), **Jira** (API token with `issueComment` permission), **Slack** (OAuth2 with `chat:write`).\n2. Wire your Jira automation rule to POST to this workflow's webhook URL.\n3. Replace every \u26a0\ufe0f placeholder called out in the green setup notes next to each relevant node (Slack `channelId`, Jira domain, vendor-URL custom field ID).\n4. Activate the workflow and open a test ticket.\n\nTypical run: ~60\u2013120s end-to-end, ~$0.03\u2013$0.08 per vendor (OpenRouter usage)."
      },
      "typeVersion": 1
    },
    {
      "id": "412a9ae2-b43b-4d59-9702-9dfcb3a5cce5",
      "name": "\u26a0\ufe0f Replace customfield_12270",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        352,
        2112
      ],
      "parameters": {
        "color": 6,
        "width": 340,
        "content": "### \u26a0\ufe0f Replace `customfield_12270`\nThis prompt references our Jira \"Vendor URL\" field ID. **Change it** to match the custom-field ID used in your Jira instance, otherwise the agent won't find the URL."
      },
      "typeVersion": 1
    },
    {
      "id": "bd3951e9-7aec-4061-866b-f0de40a55e4b",
      "name": "\u26a0\ufe0f Replace YOUR-JIRA-DOMAIN",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4016,
        1728
      ],
      "parameters": {
        "color": 6,
        "width": 324,
        "height": 180,
        "content": "### \u26a0\ufe0f Replace `YOUR-JIRA-DOMAIN`\nThe agent's prompt builds a Jira link using `YOUR-JIRA-DOMAIN.atlassian.net`. **Replace it** with your Atlassian domain (e.g. `acme.atlassian.net`), otherwise the \"View Report\" button in Slack will 404."
      },
      "typeVersion": 1
    },
    {
      "id": "2cd083ed-bead-4851-ab12-4ff6344a5299",
      "name": "\u26a0\ufe0f Set Slack channel ID",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4768,
        1728
      ],
      "parameters": {
        "color": 6,
        "width": 244,
        "height": 180,
        "content": "### \u26a0\ufe0f Set Slack `channelId`\nThe Channel ID is empty by default. **Set it** to your security channel's ID, otherwise the Slack post will fail silently."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "4b64fa22-952b-4de5-8a62-6e6573321b19",
  "connections": {
    "Aggregate": {
      "main": [
        [
          {
            "node": "Lead Security Analyst",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Pricing Agent": {
      "main": [
        [
          {
            "node": "Merge agent outputs",
            "type": "main",
            "index": 5
          }
        ]
      ]
    },
    "Process values": {
      "main": [
        [
          {
            "node": "Add required fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compliance Agent": {
      "main": [
        [
          {
            "node": "Merge agent outputs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Jira task webhook": {
      "main": [
        [
          {
            "node": "Extract vendor identity",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Availability Agent": {
      "main": [
        [
          {
            "node": "Merge agent outputs",
            "type": "main",
            "index": 4
          }
        ]
      ]
    },
    "Discover seed URLs": {
      "main": [
        [
          {
            "node": "Parse discovery JSON",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add required fields": {
      "main": [
        [
          {
            "node": "Discover seed URLs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Company Intel Agent": {
      "main": [
        [
          {
            "node": "Merge agent outputs",
            "type": "main",
            "index": 6
          }
        ]
      ]
    },
    "Data Handling Agent": {
      "main": [
        [
          {
            "node": "Merge agent outputs",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge agent outputs": {
      "main": [
        [
          {
            "node": "Sanitize agent JSON",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sanitize agent JSON": {
      "main": [
        [
          {
            "node": "Unwrap synthesis payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Unwrap final report": {
      "main": [
        [
          {
            "node": "Comment on Jira ticket",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse discovery JSON": {
      "main": [
        [
          {
            "node": "Unwrap discovery payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "perplexity_sub_agent": {
      "ai_tool": [
        [
          {
            "node": "Discover seed URLs",
            "type": "ai_tool",
            "index": 0
          },
          {
            "node": "Compliance Agent",
            "type": "ai_tool",
            "index": 0
          },
          {
            "node": "Data Handling Agent",
            "type": "ai_tool",
            "index": 0
          },
          {
            "node": "Security Controls Agent",
            "type": "ai_tool",
            "index": 0
          },
          {
            "node": "Availability Agent",
            "type": "ai_tool",
            "index": 0
          },
          {
            "node": "Pricing Agent",
            "type": "ai_tool",
            "index": 0
          },
          {
            "node": "Company Intel Agent",
            "type": "ai_tool",
            "index": 0
          },
          {
            "node": "Privacy & Legal Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Lead Security Analyst": {
      "main": [
        [
          {
            "node": "Unwrap final report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Privacy & Legal Agent": {
      "main": [
        [
          {
            "node": "Merge agent outputs",
            "type": "main",
            "index": 2
          }
        ]
      ]
    },
    "Comment on Jira ticket": {
      "main": [
        [
          {
            "node": "Post to Slack channel",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract vendor identity": {
      "main": [
        [
          {
            "node": "Process values",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Grok 4 Fast (extractor)": {
      "ai_languageModel": [
        [
          {
            "node": "Extract vendor identity",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Security Controls Agent": {
      "main": [
        [
          {
            "node": "Merge agent outputs",
            "type": "main",
            "index": 3
          }
        ]
      ]
    },
    "Unwrap discovery payload": {
      "main": [
        [
          {
            "node": "Compliance Agent",
            "type": "main",
            "index": 0
          },
          {
            "node": "Data Handling Agent",
            "type": "main",
            "index": 0
          },
          {
            "node": "Privacy & Legal Agent",
            "type": "main",
            "index": 0
          },
          {
            "node": "Security Controls Agent",
            "type": "main",
            "index": 0
          },
          {
            "node": "Availability Agent",
            "type": "main",
            "index": 0
          },
          {
            "node": "Pricing Agent",
            "type": "main",
            "index": 0
          },
          {
            "node": "Company Intel Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Unwrap synthesis payload": {
      "main": [
        [
          {
            "node": "Aggregate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Grok 4 Fast (synthesizer)": {
      "ai_languageModel": [
        [
          {
            "node": "Lead Security Analyst",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Claude Sonnet 4.5 (workers)": {
      "ai_languageModel": [
        [
          {
            "node": "Data Handling Agent",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "Privacy & Legal Agent",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "Security Controls Agent",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "Availability Agent",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "Pricing Agent",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "Company Intel Agent",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "Compliance Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Claude Sonnet 4.5 (discovery)": {
      "ai_languageModel": [
        [
          {
            "node": "Discover seed URLs",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Perplexity Sonar Pro (search)": {
      "ai_languageModel": [
        [
          {
            "node": "perplexity_sub_agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    }
  }
}

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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

When a new vendor ticket is created in Jira, this workflow automatically performs a comprehensive security due-diligence investigation and posts the findings back as a Jira comment plus a Slack notification. A Jira webhook fires when an issue is created. An AI agent (Grok)…

Source: https://n8n.io/workflows/15029/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

Who is this for? Agencies, consultants, and service providers who conduct discovery calls and need to quickly turn conversations into professional proposals.

Tool Think, Tool Calculator, Agent Tool +18
AI & RAG

This workflow automates end-to-end AI-driven content moderation for platforms managing user-generated content, including marketplaces, communities, and enterprise systems. It is designed for product,

Agent, OpenAI Chat, Output Parser Structured +4
AI & RAG

This workflow automates student academic advising by deploying a multi-agent AI system that triages student queries, routes them intelligently, and escalates when human intervention is needed. Designe

Agent, OpenAI Chat, Output Parser Structured +3
AI & RAG

This workflow automates legislative compliance analysis by coordinating multiple specialized OpenAI agents to interpret regulatory documents, evaluate organizational impact, and manage stakeholder com

HTTP Request, OpenAI Chat, Output Parser Structured +4
AI & RAG

This workflow automates comprehensive data validation and regulatory compliance reporting through intelligent AI-driven analysis. Designed for compliance officers, data governance teams, and regulator

Agent, Agent Tool, Anthropic Chat +5