AutomationFlowsAI & RAG › Cve Learning Pipeline

Cve Learning Pipeline

Cve Learning Pipeline. Uses httpRequest, chainLlm, lmChatOllama, anthropic. Scheduled trigger; 24 nodes.

Cron / scheduled trigger★★★★☆ complexityAI-powered24 nodesHTTP RequestChain LlmOllama ChatAnthropicNotion
AI & RAG Trigger: Cron / scheduled Nodes: 24 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow follows the Chainllm → HTTP Request 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
{
  "name": "My workflow",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 22
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        -288,
        16
      ],
      "id": "aff61066-b43b-4a38-8b9d-dc65d5dfb18d",
      "name": "Schedule Trigger",
      "notesInFlow": true,
      "alwaysOutputData": false
    },
    {
      "parameters": {
        "url": "https://services.nvd.nist.gov/rest/json/cves/2.0",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "pubStartDate",
              "value": "={{$now.minus({days:7}).toISO()}}"
            },
            {
              "name": "pubEndDate",
              "value": "={{$now.toISO()}}"
            },
            {
              "name": "resultsPerPage",
              "value": "20"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        -80,
        16
      ],
      "id": "6ce1225e-b264-4ced-ab94-5c6771a580a9",
      "name": "NVD CVE"
    },
    {
      "parameters": {
        "jsCode": "const input = $input.first();\nconst data = input.json;\nconst vulns = data.vulnerabilities || [];\n\nfunction getEnglishDescription(descriptions) {\n  if (!Array.isArray(descriptions)) return \"\";\n  const en = descriptions.find(d => d.lang === \"en\");\n  if (en && en.value) return en.value;\n  return descriptions.map(d => d.value).join(\" \");\n}\n\nfunction detectStack(text) {\n  const t = String(text || '').toLowerCase();\n  const tags = [];\n\n  // PHP ecosystem\n  if (/(php|laravel|thinkphp|wordpress|joomla|drupal|phpmyadmin|symfony|wpforo|woocommerce|magento)/.test(t)) {\n    tags.push(\"PHP\");\n  }\n\n  // Java ecosystem\n  if (/(java|spring|spring boot|struts|tomcat|jboss|weblogic|fastjson|log4j|jsp|java servlet|jenkins|jackson)/.test(t)) {\n    tags.push(\"Java\");\n  }\n\n  // ASP.NET ecosystem\n  if (/(asp\\.net|aspnet|\\.net|viewstate|iis|sharepoint|exchange|dotnet|c#|sitecore)/.test(t)) {\n    tags.push(\"ASP.NET\");\n  }\n\n  return [...new Set(tags)];\n}\n\nfunction detectVulnType(text) {\n  const t = String(text || '').toLowerCase();\n\n  if (/remote code execution|rce/.test(t)) return \"RCE\";\n  if (/deserialization|deserialize|unserialize/.test(t)) return \"Deserialization\";\n  if (/sql injection/.test(t)) return \"SQL Injection\";\n  if (/command injection/.test(t)) return \"Command Injection\";\n  if (/path traversal|directory traversal/.test(t)) return \"Path Traversal\";\n  if (/file inclusion|local file inclusion|remote file inclusion/.test(t)) return \"File Inclusion\";\n  if (/cross-site scripting|xss/.test(t)) return \"XSS\";\n  if (/server-side request forgery|ssrf/.test(t)) return \"SSRF\";\n  if (/authentication bypass|auth bypass/.test(t)) return \"Auth Bypass\";\n  if (/file upload/.test(t)) return \"File Upload\";\n  if (/template injection/.test(t)) return \"Template Injection\";\n  if (/viewstate/.test(t)) return \"ViewState\";\n  if (/ognl/.test(t)) return \"OGNL Injection\";\n  if (/jndi/.test(t)) return \"JNDI Injection\";\n  if (/xxe|xml external entity/.test(t)) return \"XXE\";\n  if (/open redirect/.test(t)) return \"Open Redirect\";\n  if (/csrf|cross-site request forgery/.test(t)) return \"CSRF\";\n\n  return \"Other\";\n}\n\nfunction getCvss(cve) {\n  return (\n    cve?.metrics?.cvssMetricV31?.[0]?.cvssData?.baseScore ||\n    cve?.metrics?.cvssMetricV30?.[0]?.cvssData?.baseScore ||\n    cve?.metrics?.cvssMetricV2?.[0]?.cvssData?.baseScore ||\n    0\n  );\n}\n\nfunction scoreItem(text, cvss, stack, vulnType) {\n  const t = String(text || '').toLowerCase();\n  let score = 0;\n\n  if (stack.length > 0) score += 2;\n\n  if (/remote code execution|rce/.test(t)) score += 3;\n  if (/deserialization|deserialize|unserialize/.test(t)) score += 2;\n  if (/auth bypass|authentication bypass/.test(t)) score += 2;\n  if (/file upload|template injection|viewstate|ognl|jndi|sql injection|file inclusion|xxe/.test(t)) score += 2;\n\n  if (cvss >= 9) score += 3;\n  else if (cvss >= 7) score += 2;\n  else if (cvss >= 5) score += 1;\n\n  if ([\n    \"RCE\",\n    \"Deserialization\",\n    \"SQL Injection\",\n    \"Command Injection\",\n    \"File Inclusion\",\n    \"Auth Bypass\",\n    \"Template Injection\",\n    \"ViewState\",\n    \"OGNL Injection\",\n    \"JNDI Injection\",\n    \"XXE\"\n  ].includes(vulnType)) {\n    score += 1;\n  }\n\n  return score;\n}\n\nfunction extractReferences(cve) {\n  const refs = cve?.references || [];\n\n  const allRefs = refs\n    .map(r => ({\n      url: r.url || \"\",\n      source: r.source || \"\",\n      tags: r.tags || []\n    }))\n    .filter(r => r.url);\n\n  const pocLinks = allRefs.filter(r => {\n    const u = r.url.toLowerCase();\n    return (\n      u.includes(\"github.com\") ||\n      u.includes(\"exploit-db.com\") ||\n      u.includes(\"packetstormsecurity.com\") ||\n      u.includes(\"0day.today\") ||\n      u.includes(\"gist.github.com\") ||\n      u.includes(\"gitlab.com\")\n    );\n  });\n\n  const advisoryLinks = allRefs.filter(r => {\n    const u = r.url.toLowerCase();\n    return !(\n      u.includes(\"github.com\") ||\n      u.includes(\"exploit-db.com\") ||\n      u.includes(\"packetstormsecurity.com\") ||\n      u.includes(\"0day.today\") ||\n      u.includes(\"gist.github.com\") ||\n      u.includes(\"gitlab.com\")\n    );\n  });\n\n  return {\n    allRefs,\n    pocLinks,\n    advisoryLinks\n  };\n}\n\nconst out = [];\n\nfor (const item of vulns) {\n  const cve = item.cve;\n  if (!cve) continue;\n\n  const description = getEnglishDescription(cve.descriptions || []);\n  const stack = detectStack(description);\n\n  // \u53ea\u4fdd\u7559 PHP / Java / ASP.NET\n  if (stack.length === 0) continue;\n\n  const vulnType = detectVulnType(description);\n  const cvss = getCvss(cve);\n  const score = scoreItem(description, cvss, stack, vulnType);\n\n  const { allRefs, pocLinks, advisoryLinks } = extractReferences(cve);\n\n  out.push({\n    json: {\n      cveId: cve.id || \"\",\n      description,\n      stack,\n      vulnType,\n      cvss,\n      score,\n      published: cve.published || \"\",\n      modified: cve.lastModified || \"\",\n      nvdUrl: cve.id ? `https://nvd.nist.gov/vuln/detail/${cve.id}` : \"\",\n      references: allRefs,\n      advisoryLinks,\n      pocLinks,\n      hasPublicPocCandidate: pocLinks.length > 0\n    }\n  });\n}\n\nreturn out;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        128,
        16
      ],
      "id": "7a106a04-78b0-420e-bda0-53a463ae2012",
      "name": "filter and score"
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "leftValue": "={{$json.premium}}",
                    "rightValue": "true",
                    "operator": {
                      "type": "boolean",
                      "operation": "true",
                      "singleValue": true
                    },
                    "id": "abda42ee-91d8-4a85-a8ec-01f903ef3503"
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "anthropic"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "03afc28a-4fe7-4c67-a5af-463779a165f7",
                    "leftValue": "={{$json.premium}}",
                    "rightValue": false,
                    "operator": {
                      "type": "boolean",
                      "operation": "false",
                      "singleValue": true
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "ollama"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.4,
      "position": [
        1520,
        128
      ],
      "id": "e09dd35b-f9c5-45e3-83f0-aed87bdc522c",
      "name": "Switch"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=\u4f60\u662f\u4e00\u4f4d\u8cc7\u5b89\u6f0f\u6d1e\u5206\u6790\u52a9\u624b\u3002\n\n\u8acb\u6839\u64da\u4ee5\u4e0b\u6f0f\u6d1e\u8cc7\u8a0a\u8f38\u51fa\u300c\u5b78\u7fd2\u7b46\u8a18\u300d\u3002\n\n\u8acb\u7528\u4ee5\u4e0b\u683c\u5f0f\u56de\u7b54\uff1a\n\n\u6f0f\u6d1e\u6458\u8981:\n(\u4e00\u53e5\u8a71)\n\n\u6f0f\u6d1e\u539f\u7406:\n(\u7c21\u77ed\u8aaa\u660e)\n\n\u653b\u64ca\u6d41\u7a0b:\n1.\n2.\n3.\n\n\u53ef\u80fd\u7684 Exploit Payload:\n(\u7c21\u55ae\u4f8b\u5b50)\n\n\u4fee\u88dc\u65b9\u5f0f:\n(\u5982\u4f55\u4fee\u88dc)\n\n\u5b78\u7fd2\u91cd\u9ede:\n(\u5217\u51fa3\u500b\u76f8\u95dc\u6280\u8853)\n\n\u8acb\u4f7f\u7528\u7e41\u9ad4\u4e2d\u6587\u3002\n\n\u6f0f\u6d1e\u8cc7\u8a0a:\n{{$json.description}}",
        "messages": {
          "messageValues": [
            {
              "message": "=\u4f60\u662f\u4e00\u4f4d\u8cc7\u5b89\u6f0f\u6d1e\u5206\u6790\u52a9\u624b\uff0c\u5c08\u9580\u628a CVE \u6574\u7406\u6210\u9069\u5408\u521d\u5b78\u8005\u5b78\u7fd2\u7684\u7b46\u8a18\u3002\n\n\u8acb\u9075\u5b88\u4ee5\u4e0b\u898f\u5247\uff1a\n1. \u4e00\u5f8b\u4f7f\u7528\u7e41\u9ad4\u4e2d\u6587\u3002\n2. \u5167\u5bb9\u8981\u6e05\u695a\u3001\u7c21\u6f54\u3001\u7d50\u69cb\u5316\u3002\n3. \u4e0d\u8981\u63d0\u4f9b\u53ef\u76f4\u63a5\u653b\u64ca\u4ed6\u4eba\u7684\u5177\u9ad4\u5229\u7528\u6b65\u9a5f\u3002\n4. \u53ef\u4ee5\u7528\u9ad8\u5c64\u6b21\u65b9\u5f0f\u8aaa\u660e\u653b\u64ca\u6d41\u7a0b\u8207\u53ef\u80fd\u7684 payload \u985e\u578b\uff0c\u4f46\u4e0d\u8981\u7d66\u5b8c\u6574\u53ef\u76f4\u63a5\u57f7\u884c\u7684 exploit\u3002\n5. \u8acb\u56b4\u683c\u4f9d\u7167\u4f7f\u7528\u8005\u6307\u5b9a\u7684\u683c\u5f0f\u8f38\u51fa\u3002\n6. \u82e5\u8cc7\u8a0a\u4e0d\u8db3\uff0c\u660e\u78ba\u5beb\u51fa\u300c\u8cc7\u8a0a\u4e0d\u8db3\u300d\u3002\n7. \u91cd\u9ede\u653e\u5728\uff1a\u6f0f\u6d1e\u539f\u7406\u3001\u653b\u64ca\u601d\u8def\u3001\u4fee\u88dc\u65b9\u5f0f\u3001\u5b78\u7fd2\u91cd\u9ede\u3002\n\u8acb\u4e0d\u8981\u8f38\u51fa\u683c\u5f0f\u4ee5\u5916\u7684\u5167\u5bb9\u3002"
            }
          ]
        },
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.9,
      "position": [
        1760,
        256
      ],
      "id": "5565b49d-f666-435e-bb0f-198b0ec5199b",
      "name": "Basic LLM Chain"
    },
    {
      "parameters": {
        "model": "llama3.1:8b",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOllama",
      "typeVersion": 1,
      "position": [
        1872,
        464
      ],
      "id": "a0f1dadc-ceea-4254-b827-9c55f6d9d905",
      "name": "Ollama Chat Model",
      "credentials": {
        "ollamaApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "modelId": {
          "__rl": true,
          "value": "claude-sonnet-4-6",
          "mode": "list",
          "cachedResultName": "claude-sonnet-4-6"
        },
        "messages": {
          "values": [
            {
              "content": "=\u4f60\u662f\u4e00\u4f4d\u8cc7\u5b89\u7814\u7a76\u54e1\u8207\u6f0f\u6d1e\u5206\u6790\u5c08\u5bb6\u3002\n\n\u8acb\u5206\u6790\u4ee5\u4e0b\u6f0f\u6d1e\u8cc7\u8a0a\uff0c\u4e26\u7528\u300c\u6f0f\u6d1e\u5b78\u7fd2\u7b46\u8a18\u300d\u65b9\u5f0f\u6574\u7406\u3002\n\n\u8acb\u8f38\u51fa\u4ee5\u4e0b\u6bb5\u843d\uff1a\n\n\u6f0f\u6d1e\u6458\u8981\uff1a\n\u7c21\u55ae\u63cf\u8ff0\u6f0f\u6d1e\u3002\n\n\u6f0f\u6d1e\u539f\u7406\uff1a\n\u89e3\u91cb\u70ba\u4ec0\u9ebc\u6703\u51fa\u73fe\u9019\u500b\u6f0f\u6d1e\u3002\n\n\u653b\u64ca\u6d41\u7a0b\uff1a\n\u653b\u64ca\u8005\u5982\u4f55\u5229\u7528\u9019\u500b\u6f0f\u6d1e\u3002\n\n\u53ef\u80fd\u7684 Exploit Payload\uff1a\n\u8209\u4f8b\u53ef\u80fd\u7684 payload \u6216\u5229\u7528\u65b9\u5f0f\u3002\n\n\u4fee\u88dc\u65b9\u5f0f\uff1a\n\u958b\u767c\u8005\u61c9\u5982\u4f55\u4fee\u88dc\u3002\n\n\u5b78\u7fd2\u91cd\u9ede\uff1a\n\u8aaa\u660e\u9019\u500b\u6f0f\u6d1e\u5c6c\u65bc\u54ea\u4e00\u7a2e\u6f0f\u6d1e\u5bb6\u65cf\uff0c\u4ee5\u53ca\u76f8\u95dc\u6280\u8853\u3002\n\n\u8acb\u4f7f\u7528\u7e41\u9ad4\u4e2d\u6587\u56de\u7b54\u3002\n\n\u6f0f\u6d1e\u8cc7\u8a0a\uff1a\n{{$json.description}}"
            }
          ]
        },
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.anthropic",
      "typeVersion": 1,
      "position": [
        1760,
        48
      ],
      "id": "ceb20c72-b6f6-4966-a7a7-a66bc93c9957",
      "name": "Message a model",
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const items = $input.all();\n\nitems.sort((a, b) => {\n  return (b.json.score || 0) - (a.json.score || 0);\n});\n\nreturn items.slice(0, 3);"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        336,
        16
      ],
      "id": "0bb34cce-9c6d-491a-ac6f-7af271d227be",
      "name": "Top 3 web CVE"
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3.2,
      "position": [
        2528,
        160
      ],
      "id": "b59751ff-2c11-4869-9a26-321ce03fbd9b",
      "name": "Merge"
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const j = $json;\nconst packed = $items(\"Pack Original Anthropic\")[$itemIndex]?.json || {};\n\nfunction normalizeStack(stack) {\n  if (Array.isArray(stack)) return stack.join(', ');\n  if (typeof stack === 'string') return stack;\n  return '';\n}\n\nfunction normalizeLinks(links) {\n  if (Array.isArray(links)) {\n    return links\n      .map(x => {\n        if (typeof x === 'string') return x;\n        if (x && typeof x.url === 'string') return x.url;\n        return '';\n      })\n      .filter(Boolean)\n      .join('\\n');\n  }\n  if (typeof links === 'string') return links;\n  return '';\n}\n\nfunction normalizeReferences(refs) {\n  if (!Array.isArray(refs)) return '';\n  return refs\n    .map(r => {\n      if (typeof r === 'string') return r;\n      const url = r?.url || '';\n      const source = r?.source || '';\n      const tags = Array.isArray(r?.tags) ? r.tags.join(', ') : '';\n      return [url, source, tags].filter(Boolean).join(' | ');\n    })\n    .filter(Boolean)\n    .join('\\n');\n}\n\nfunction extractAnthropicSummary(obj) {\n  if (typeof obj.text === 'string' && obj.text.trim()) return obj.text.trim();\n\n  if (Array.isArray(obj.content)) {\n    const joined = obj.content\n      .map(part => {\n        if (typeof part === 'string') return part;\n        if (part && typeof part.text === 'string') return part.text;\n        return '';\n      })\n      .filter(Boolean)\n      .join('\\n');\n    if (joined.trim()) return joined.trim();\n  }\n\n  if (typeof obj.response === 'string' && obj.response.trim()) return obj.response.trim();\n  if (typeof obj.output === 'string' && obj.output.trim()) return obj.output.trim();\n\n  return '';\n}\n\nreturn {\n  cveId: packed.cveId || '',\n  stack: normalizeStack(packed.stack),\n  vulnType: packed.vulnType || '',\n  cvss: packed.cvss || 0,\n  score: packed.score || 0,\n  kev: packed.kev === true,\n  kevVendor: packed.kevVendor || '',\n  kevProduct: packed.kevProduct || '',\n  kevDueDate: packed.kevDueDate || '',\n  kevNotes: packed.kevNotes || '',\n  premium: packed.premium === true,\n  model_used: 'anthropic',\n  summary: extractAnthropicSummary(j),\n  description: packed.description || '',\n  published: packed.published || '',\n  modified: packed.modified || '',\n  nvdUrl: packed.nvdUrl || '',\n  references: normalizeReferences(packed.references),\n  pocLinks: normalizeLinks(packed.pocLinks),\n  githubLinks: normalizeLinks(packed.githubLinks),\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2112,
        48
      ],
      "id": "c4c09a94-ede5-473e-9bc2-633bf9bccc85",
      "name": "Normalize Anthropic"
    },
    {
      "parameters": {
        "url": "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        928,
        -448
      ],
      "id": "7e522e56-2763-4ebf-bbab-d3ee901ead58",
      "name": "Enrich KEV"
    },
    {
      "parameters": {
        "jsCode": "const kevList = $items(\"Enrich KEV\")[0].json.vulnerabilities || [];\nconst topItems = $items(\"Top 3 web CVE\");\n\nreturn topItems.map(item => {\n  const cveId = item.json.cveId;\n  const match = kevList.find(v => v.cveID === cveId);\n\n  return {\n    json: {\n      ...item.json,\n      kev: !!match,\n      kevVendor: match?.vendorProject || \"\",\n      kevProduct: match?.product || \"\",\n      kevDueDate: match?.dueDate || \"\",\n      kevNotes: match?.shortDescription || \"\"\n    }\n  };\n});"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        928,
        -240
      ],
      "id": "5f574406-cccd-4061-bab7-0fcf4e59dca7",
      "name": "Join KEV"
    },
    {
      "parameters": {
        "url": "=https://api.github.com/search/repositories",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "q",
              "value": "={{$json.cveId}} poc"
            },
            {
              "name": "sort",
              "value": "stars"
            },
            {
              "name": "order",
              "value": "desc"
            },
            {
              "name": "per_page",
              "value": "5"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        928,
        0
      ],
      "id": "a9075909-3fed-4ea6-9553-75105f4f12d9",
      "name": "HTTP Request"
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const repos = $json.items || [];\n\nreturn {\n  githubLinks: repos.slice(0, 5).map(r => ({\n    name: r.full_name,\n    url: r.html_url,\n    stars: r.stargazers_count,\n    description: r.description || \"\"\n  }))\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        928,
        288
      ],
      "id": "9d7c7256-13bd-4604-acc4-909b10dab8a3",
      "name": "Extract Github Links"
    },
    {
      "parameters": {
        "jsCode": "const baseItems = $items(\"Join KEV\");\nconst githubItems = $items(\"Extract Github Links\");\n\nreturn baseItems.map((item, index) => {\n  const githubLinks = githubItems[index]?.json?.githubLinks || [];\n\n  return {\n    json: {\n      ...item.json,\n      githubLinks\n    }\n  };\n});"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        928,
        528
      ],
      "id": "d16f2e14-0b17-47f6-8c2b-e4d2d9bc6c50",
      "name": "Join Github"
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const j = $json;\nconst githubCount = Array.isArray(j.githubLinks) ? j.githubLinks.length : 0;\nconst stack = Array.isArray(j.stack) ? j.stack : [];\nconst vulnType = j.vulnType || \"\";\n\nlet premium = false;\n\nif ((j.score || 0) >= 7) premium = true;\nif (j.kev === true) premium = true;\nif (githubCount > 0 && (j.score || 0) >= 5) premium = true;\n\n// \u4f60\u7279\u5225\u60f3\u5b78\u7684\u5178\u578b\u6f0f\u6d1e\u985e\u578b\uff0c\u76f4\u63a5\u5347\u7d1a\nif ([\n  \"RCE\",\n  \"Deserialization\",\n  \"SQL Injection\",\n  \"File Inclusion\",\n  \"Auth Bypass\",\n  \"Template Injection\",\n  \"ViewState\",\n  \"OGNL Injection\",\n  \"JNDI Injection\"\n].includes(vulnType)) {\n  premium = true;\n}\n\nreturn {\n  ...j,\n  githubCount,\n  premium\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1264,
        336
      ],
      "id": "77aec9b6-e3c1-4b3b-b289-6971e45cb5ea",
      "name": "Set Premium Route"
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const j = $json;\nconst packed = $items(\"Pack Original Ollama\")[$itemIndex]?.json || {};\n\nfunction normalizeStack(stack) {\n  if (Array.isArray(stack)) return stack.join(', ');\n  if (typeof stack === 'string') return stack;\n  return '';\n}\n\nfunction normalizeLinks(links) {\n  if (Array.isArray(links)) {\n    return links\n      .map(x => {\n        if (typeof x === 'string') return x;\n        if (x && typeof x.url === 'string') return x.url;\n        return '';\n      })\n      .filter(Boolean)\n      .join('\\n');\n  }\n  if (typeof links === 'string') return links;\n  return '';\n}\n\nfunction normalizeReferences(refs) {\n  if (!Array.isArray(refs)) return '';\n  return refs\n    .map(r => {\n      if (typeof r === 'string') return r;\n      const url = r?.url || '';\n      const source = r?.source || '';\n      const tags = Array.isArray(r?.tags) ? r.tags.join(', ') : '';\n      return [url, source, tags].filter(Boolean).join(' | ');\n    })\n    .filter(Boolean)\n    .join('\\n');\n}\n\nfunction extractOllamaSummary(obj) {\n  if (typeof obj.text === 'string' && obj.text.trim()) return obj.text.trim();\n  if (typeof obj.response === 'string' && obj.response.trim()) return obj.response.trim();\n  if (typeof obj.output === 'string' && obj.output.trim()) return obj.output.trim();\n  if (obj.message && typeof obj.message.content === 'string' && obj.message.content.trim()) {\n    return obj.message.content.trim();\n  }\n  return '';\n}\n\nreturn {\n  cveId: packed.cveId || '',\n  stack: normalizeStack(packed.stack),\n  vulnType: packed.vulnType || '',\n  cvss: packed.cvss || 0,\n  score: packed.score || 0,\n  kev: packed.kev === true,\n  kevVendor: packed.kevVendor || '',\n  kevProduct: packed.kevProduct || '',\n  kevDueDate: packed.kevDueDate || '',\n  kevNotes: packed.kevNotes || '',\n  premium: packed.premium === true,\n  model_used: 'ollama',\n  summary: extractOllamaSummary(j),\n  description: packed.description || '',\n  published: packed.published || '',\n  modified: packed.modified || '',\n  nvdUrl: packed.nvdUrl || '',\n  references: normalizeReferences(packed.references),\n  pocLinks: normalizeLinks(packed.pocLinks),\n  githubLinks: normalizeLinks(packed.githubLinks),\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2112,
        256
      ],
      "id": "d306b01f-c4fe-4b74-8c41-cea9f64452da",
      "name": "Normalize Ollama"
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const j = $json;\n\nfunction safe(v) {\n  if (v === undefined || v === null) return \"\";\n  return v;\n}\n\nfunction dateOnly(d) {\n  if (!d) return \"\";\n  return String(d).split(\"T\")[0];\n}\n\nreturn {\n  title: j.cveId,\n\n  stack: safe(j.stack),\n  vulnType: safe(j.vulnType),\n\n  cvss: j.cvss || 0,\n  score: j.score || 0,\n\n  kev: j.kev === true,\n\n  kevVendor: safe(j.kevVendor),\n  kevProduct: safe(j.kevProduct),\n\n  model: safe(j.model_used),\n\n  summary: safe(j.summary),\n  description: safe(j.description),\n\n  published: dateOnly(j.published),\n  modified: safe(j.modified),\n\n  nvdUrl: safe(j.nvdUrl),\n\n  references: safe(j.references),\n  pocLinks: safe(j.pocLinks),\n  githubLinks: safe(j.githubLinks)\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2768,
        320
      ],
      "id": "bc27d74f-b88f-42b6-b035-3ecb2490ec0e",
      "name": "Prepare Notion"
    },
    {
      "parameters": {
        "jsCode": "const j = $json;\n\nreturn {\n  ...j,\n  originalData: {\n    cveId: j.cveId || '',\n    stack: j.stack || [],\n    vulnType: j.vulnType || '',\n    cvss: j.cvss || 0,\n    score: j.score || 0,\n    kev: j.kev === true,\n    kevVendor: j.kevVendor || '',\n    kevProduct: j.kevProduct || '',\n    kevDueDate: j.kevDueDate || '',\n    kevNotes: j.kevNotes || '',\n    premium: j.premium === true,\n    description: j.description || '',\n    published: j.published || '',\n    modified: j.modified || '',\n    nvdUrl: j.nvdUrl || '',\n    references: j.references || [],\n    pocLinks: j.pocLinks || [],\n    githubLinks: j.githubLinks || []\n  }\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1584,
        336
      ],
      "id": "861345e7-2d0c-4d7f-9470-157d0ed6767f",
      "name": "Pack Original Ollama"
    },
    {
      "parameters": {
        "jsCode": "const j = $json;\n\nreturn {\n  ...j,\n  originalData: {\n    cveId: j.cveId || '',\n    stack: j.stack || [],\n    vulnType: j.vulnType || '',\n    cvss: j.cvss || 0,\n    score: j.score || 0,\n    kev: j.kev === true,\n    kevVendor: j.kevVendor || '',\n    kevProduct: j.kevProduct || '',\n    kevDueDate: j.kevDueDate || '',\n    kevNotes: j.kevNotes || '',\n    premium: j.premium === true,\n    description: j.description || '',\n    published: j.published || '',\n    modified: j.modified || '',\n    nvdUrl: j.nvdUrl || '',\n    references: j.references || [],\n    pocLinks: j.pocLinks || [],\n    githubLinks: j.githubLinks || []\n  }\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1632,
        -64
      ],
      "id": "9e7ba70e-8bcb-43a4-b2e2-899aa399f4e4",
      "name": "Pack Original Anthropic"
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const j = $json;\n\nfunction safe(v) {\n  if (v === undefined || v === null) return \"\";\n  return String(v);\n}\n\nfunction yesNo(v) {\n  return v ? \"Yes\" : \"No\";\n}\n\nfunction section(title, content) {\n  const text = safe(content).trim();\n  if (!text) return \"\";\n  return `## ${title}\\n${text}\\n\\n`;\n}\n\nconst markdown = `# ${safe(j.cveId)}\n\n- **Stack:** ${safe(j.stack)}\n- **Vulnerability Type:** ${safe(j.vulnType)}\n- **CVSS:** ${safe(j.cvss)}\n- **Score:** ${safe(j.score)}\n- **KEV:** ${yesNo(j.kev)}\n- **Model:** ${safe(j.model_used)}\n\n${section(\"AI Summary\", j.summary)}\n${section(\"Technical Description\", j.description)}\n${section(\"NVD\", j.nvdUrl)}\n${section(\"References\", j.references)}\n${section(\"PoC Links\", j.pocLinks)}\n${section(\"GitHub Links\", j.githubLinks)}\n${section(\n  \"KEV Information\",\n  [\n    j.kevVendor ? `Vendor: ${j.kevVendor}` : \"\",\n    j.kevProduct ? `Product: ${j.kevProduct}` : \"\",\n    j.kevDueDate ? `Due Date: ${j.kevDueDate}` : \"\",\n    j.kevNotes ? `Notes: ${j.kevNotes}` : \"\",\n  ].filter(Boolean).join(\"\\n\")\n)}\n${section(\n  \"Timeline\",\n  [\n    j.published ? `Published: ${j.published}` : \"\",\n    j.modified ? `Modified: ${j.modified}` : \"\",\n  ].filter(Boolean).join(\"\\n\")\n)}\n`;\n\nreturn {\n  ...j,\n  markdown\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2768,
        0
      ],
      "id": "dd6f6713-145b-4756-89b9-bbcc8d048d78",
      "name": "Generate Markdown"
    },
    {
      "parameters": {
        "resource": "databasePage",
        "databaseId": {
          "__rl": true,
          "value": "",
          "mode": "id"
        },
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "title|rich_text",
              "textContent": "={{$json.title}}"
            },
            {
              "key": "Stack|rich_text",
              "textContent": "={{$json.stack}}"
            },
            {
              "key": "VulnType|rich_text",
              "textContent": "={{$json.vulnType}}"
            },
            {
              "key": "CVSS|number",
              "numberValue": "={{$json.cvss}}"
            },
            {
              "key": "Score|number",
              "numberValue": "={{$json.score}}"
            },
            {
              "key": "Kev|checkbox",
              "checkboxValue": "={{$json.kev}}"
            },
            {
              "key": "KevVendor|rich_text",
              "textContent": "={{$json.kevVendor}}"
            },
            {
              "key": "KevProduct|rich_text",
              "textContent": "={{$json.kevProduct}}"
            },
            {
              "key": "Model|rich_text",
              "textContent": "={{$json.model}}"
            },
            {
              "key": "Summary|rich_text",
              "textContent": "={{$json.summary}}"
            },
            {
              "key": "Desciption|rich_text",
              "textContent": "={{$json.description}}"
            },
            {
              "key": "Published|rich_text",
              "textContent": "={{$json.published}}"
            },
            {
              "key": "Modified|rich_text",
              "textContent": "={{$json.modified}}"
            },
            {
              "key": "NVDUrl|url",
              "urlValue": "={{$json.nvdUrl}}"
            },
            {
              "key": "References|rich_text",
              "textContent": "={{$json.references}}"
            },
            {
              "key": "PoC Links|rich_text",
              "textContent": "={{$json.pocLinks}}"
            },
            {
              "key": "Github Links|rich_text",
              "textContent": "={{$json.githubLinks}}"
            },
            {
              "key": "Fetch Time|date",
              "date": "={{$now}}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.notion",
      "typeVersion": 2.2,
      "position": [
        2976,
        320
      ],
      "id": "ba1e41e1-a88c-42e1-a89e-85539e3c2a16",
      "name": "Create a database page",
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const j = $json;\n\nfunction rt(content) {\n  return [\n    {\n      type: \"text\",\n      text: {\n        content: String(content || \"\")\n      }\n    }\n  ];\n}\n\nconst blocks = [];\n\n// Title section\nblocks.push({\n  type: \"heading_1\",\n  heading_1: {\n    rich_text: rt(j.cveId || \"Unknown CVE\")\n  }\n});\n\n// Overview\nblocks.push({\n  type: \"heading_2\",\n  heading_2: {\n    rich_text: rt(\"Overview\")\n  }\n});\n\nblocks.push({\n  type: \"bulleted_list_item\",\n  bulleted_list_item: {\n    rich_text: rt(`Stack: ${j.stack || \"\"}`)\n  }\n});\n\nblocks.push({\n  type: \"bulleted_list_item\",\n  bulleted_list_item: {\n    rich_text: rt(`Vulnerability Type: ${j.vulnType || \"\"}`)\n  }\n});\n\nblocks.push({\n  type: \"bulleted_list_item\",\n  bulleted_list_item: {\n    rich_text: rt(`CVSS: ${j.cvss || \"\"}`)\n  }\n});\n\nblocks.push({\n  type: \"bulleted_list_item\",\n  bulleted_list_item: {\n    rich_text: rt(`Score: ${j.score || \"\"}`)\n  }\n});\n\nblocks.push({\n  type: \"bulleted_list_item\",\n  bulleted_list_item: {\n    rich_text: rt(`KEV: ${j.kev ? \"Yes\" : \"No\"}`)\n  }\n});\n\nblocks.push({\n  type: \"bulleted_list_item\",\n  bulleted_list_item: {\n    rich_text: rt(`Model: ${j.model_used || \"\"}`)\n  }\n});\n\n// AI Summary\nif (j.summary) {\n  blocks.push({\n    type: \"heading_2\",\n    heading_2: {\n      rich_text: rt(\"AI Summary\")\n    }\n  });\n\n  blocks.push({\n    type: \"paragraph\",\n    paragraph: {\n      rich_text: rt(j.summary)\n    }\n  });\n}\n\n// Technical Description\nif (j.description) {\n  blocks.push({\n    type: \"heading_2\",\n    heading_2: {\n      rich_text: rt(\"Technical Description\")\n    }\n  });\n\n  blocks.push({\n    type: \"paragraph\",\n    paragraph: {\n      rich_text: rt(j.description)\n    }\n  });\n}\n\n// References\nif (j.nvdUrl || j.references) {\n  blocks.push({\n    type: \"heading_2\",\n    heading_2: {\n      rich_text: rt(\"References\")\n    }\n  });\n\n  if (j.nvdUrl) {\n    blocks.push({\n      type: \"paragraph\",\n      paragraph: {\n        rich_text: rt(`NVD: ${j.nvdUrl}`)\n      }\n    });\n  }\n\n  if (j.references) {\n    blocks.push({\n      type: \"paragraph\",\n      paragraph: {\n        rich_text: rt(j.references)\n      }\n    });\n  }\n}\n\n// PoC Links\nif (j.pocLinks) {\n  blocks.push({\n    type: \"heading_2\",\n    heading_2: {\n      rich_text: rt(\"PoC Links\")\n    }\n  });\n\n  blocks.push({\n    type: \"paragraph\",\n    paragraph: {\n      rich_text: rt(j.pocLinks)\n    }\n  });\n}\n\n// GitHub Links\nif (j.githubLinks) {\n  blocks.push({\n    type: \"heading_2\",\n    heading_2: {\n      rich_text: rt(\"GitHub Links\")\n    }\n  });\n\n  blocks.push({\n    type: \"paragraph\",\n    paragraph: {\n      rich_text: rt(j.githubLinks)\n    }\n  });\n}\n\n// KEV Information\nif (j.kevVendor || j.kevProduct || j.kevDueDate || j.kevNotes) {\n  blocks.push({\n    type: \"heading_2\",\n    heading_2: {\n      rich_text: rt(\"KEV Information\")\n    }\n  });\n\n  const kevText = [\n    j.kevVendor ? `Vendor: ${j.kevVendor}` : \"\",\n    j.kevProduct ? `Product: ${j.kevProduct}` : \"\",\n    j.kevDueDate ? `Due Date: ${j.kevDueDate}` : \"\",\n    j.kevNotes ? `Notes: ${j.kevNotes}` : \"\"\n  ].filter(Boolean).join(\"\\n\");\n\n  blocks.push({\n    type: \"paragraph\",\n    paragraph: {\n      rich_text: rt(kevText)\n    }\n  });\n}\n\nreturn {\n  ...j,\n  notionBlocks: blocks\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2976,
        0
      ],
      "id": "c81f9d9d-99aa-4291-b2ad-e2ddd3321550",
      "name": "Generate Notion Blocks"
    },
    {
      "parameters": {
        "pageId": {
          "__rl": true,
          "value": "",
          "mode": "url"
        },
        "title": "={{$json.cveId}} \u00b7 {{$json.stack}} \u00b7 {{$json.vulnType}}",
        "blockUi": {
          "blockValues": [
            {
              "type": "heading_1",
              "textContent": "={{$json.cveId}}"
            },
            {
              "textContent": "={{\"Stack: \" + $json.stack + \"\\nType: \" + $json.vulnType + \"\\nCVSS: \" + $json.cvss + \"\\nKEV: \" + ($json.kev ? \"Yes\" : \"No\")}}"
            },
            {
              "type": "heading_2",
              "textContent": "AI Summary"
            },
            {
              "textContent": "={{$json.summary}}"
            },
            {
              "type": "heading_2",
              "textContent": "Technical Description"
            },
            {
              "textContent": "={{$json.description}}"
            },
            {
              "type": "heading_2",
              "textContent": "=References"
            },
            {
              "textContent": "={{\"NVD: \" + $json.nvdUrl + \"\\n\\n\" + ($json.githubLinks || \"\")}}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.notion",
      "typeVersion": 2.2,
      "position": [
        3184,
        0
      ],
      "id": "aef58e73-09e8-45ec-a3bf-95d008e4b16f",
      "name": "Create a page",
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "NVD CVE",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "NVD CVE": {
      "main": [
        [
          {
            "node": "filter and score",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "filter and score": {
      "main": [
        [
          {
            "node": "Top 3 web CVE",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Ollama Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Basic LLM Chain",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Switch": {
      "main": [
        [
          {
            "node": "Pack Original Anthropic",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Pack Original Ollama",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Top 3 web CVE": {
      "main": [
        [
          {
            "node": "Enrich KEV",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Message a model": {
      "main": [
        [
          {
            "node": "Normalize Anthropic",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Basic LLM Chain": {
      "main": [
        [
          {
            "node": "Normalize Ollama",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge": {
      "main": [
        [
          {
            "node": "Prepare Notion",
            "type": "main",
            "index": 0
          },
          {
            "node": "Generate Markdown",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Anthropic": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Enrich KEV": {
      "main": [
        [
          {
            "node": "Join KEV",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Join KEV": {
      "main": [
        [
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request": {
      "main": [
        [
          {
            "node": "Extract Github Links",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Github Links": {
      "main": [
        [
          {
            "node": "Join Github",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Join Github": {
      "main": [
        [
          {
            "node": "Set Premium Route",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Premium Route": {
      "main": [
        [
          {
            "node": "Switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Ollama": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Prepare Notion": {
      "main": [
        [
          {
            "node": "Create a database page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Pack Original Anthropic": {
      "main": [
        [
          {
            "node": "Message a model",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Pack Original Ollama": {
      "main": [
        [
          {
            "node": "Basic LLM Chain",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Markdown": {
      "main": [
        [
          {
            "node": "Generate Notion Blocks",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Notion Blocks": {
      "main": [
        [
          {
            "node": "Create a page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate",
    "availableInMCP": false
  },
  "versionId": "244049e0-b001-47d9-9878-c666cdcff0fa",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "",
  "tags": []
}

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

Cve Learning Pipeline. Uses httpRequest, chainLlm, lmChatOllama, anthropic. Scheduled trigger; 24 nodes.

Source: https://github.com/hack-bear-codz/CVE-learning-pipeline/blob/8e6eb27f40a0dd16274e3c4dffcb8e46473eb506/WorkFlows/workflow.json — 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

This n8n workflow automates the process of fetching, processing, and storing tech news articles from RSS feeds into a Notion database. It retrieves articles from The Verge and TechCrunch, processes th

OpenAI Chat, Chain Llm, Notion +3
AI & RAG

Fetch user-specific research papers from arXiv on a daily schedule, process and structure the data, and create or update entries in a Notion database, with support for data delivery Paper Topic: singl

Chain Llm, Google Gemini Chat, HTTP Request +3
AI & RAG

Trading bot: News Sentiment. Uses rssFeedRead, chainLlm, lmChatOllama, httpRequest. Scheduled trigger; 21 nodes.

RSS Feed Read, Chain Llm, Ollama Chat +2
AI & RAG

SaaS product managers, startup founders, and marketing teams who need to stay informed about competitor movements without manual monitoring. Perfect for teams who want to automate competitive intellig

HTTP Request, Chain Llm, Anthropic Chat +3
AI & RAG

This scheduled workflow pulls article URLs from Google Sheets, scrapes each page, uses Anthropic Claude to generate a structured news briefing, saves results to Notion, posts a compiled digest to Slac

Google Sheets, HTTP Request, Chain Llm +3