{
  "id": "VMlTs0KXsUyItPt5QWS6q",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "IP Enrichment & Country Attribution",
  "tags": [
    {
      "id": "Bd0kqXsypsQC9yhc",
      "name": "ip-enrichment",
      "createdAt": "2026-02-06T03:46:29.946Z",
      "updatedAt": "2026-02-06T03:46:29.946Z"
    },
    {
      "id": "yK4f7eZ2xqZwDV0J",
      "name": "geoip",
      "createdAt": "2026-02-06T03:46:35.614Z",
      "updatedAt": "2026-02-06T03:46:35.614Z"
    },
    {
      "id": "zxOfaJAL0NS4yvOB",
      "name": "threat-intelligence",
      "createdAt": "2026-02-06T03:46:57.910Z",
      "updatedAt": "2026-02-06T03:46:57.910Z"
    }
  ],
  "nodes": [
    {
      "id": "a97ceefb-9648-4ee2-8c9f-aa4022a1859e",
      "name": "Weebhook - Receive IP Input",
      "type": "n8n-nodes-base.webhook",
      "position": [
        0,
        0
      ],
      "parameters": {
        "path": "/ip-enrichment",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "0962527d-8e6e-41a0-998b-06bcbbd62515",
      "name": "Validate IP Address",
      "type": "n8n-nodes-base.code",
      "position": [
        208,
        0
      ],
      "parameters": {
        "jsCode": "const ip = $input.first().json.body.text;\n\nif (!ip) {\n  return [{ json: { valid: false, reason: \"IP missing\" } }];\n}\n\n// Basic IPv4 structure check\nconst ipv4Regex = /^(\\d{1,3}\\.){3}\\d{1,3}$/;\n\nlet valid = false;\n\nif (ipv4Regex.test(ip)) {\n  const octets = ip.split('.').map(Number);\n  valid = octets.every(o => o >= 0 && o <= 255);\n}\n\nreturn [{\n  json: {\n    ip,\n    valid\n  }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "a48725a9-175b-406f-8e20-efca11497663",
      "name": "If IP is Valid",
      "type": "n8n-nodes-base.if",
      "position": [
        416,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "8e64b0c1-7fc7-414f-9179-fe522c20f035",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.valid }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "1e36451c-047a-4b47-81c9-989f8c9293e8",
      "name": "Respond Invalid IP Address",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        416,
        224
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "{\n  \"status\": \"error\",\n  \"message\": \"Invalid IP address.\"\n}"
      },
      "typeVersion": 1.5
    },
    {
      "id": "5d15bff6-ef56-4f2c-9ad4-7a5f338c1618",
      "name": "Check Private / Internal IP",
      "type": "n8n-nodes-base.code",
      "position": [
        656,
        0
      ],
      "parameters": {
        "jsCode": "const ip = $input.first().json.ip;\n\nconst privateRanges = [\n  /^10\\./,\n  /^192\\.168\\./,\n  /^172\\.(1[6-9]|2[0-9]|3[0-1])\\./,\n  /^127\\./\n];\n\nconst isPrivate = privateRanges.some(r => r.test(ip));\n\nreturn [{\n  json: {\n    ip,\n    isPrivate\n  }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "c2be76fe-e393-421c-86a7-30ab13971161",
      "name": "If IP is Private",
      "type": "n8n-nodes-base.if",
      "position": [
        816,
        112
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "44ccbfad-d5e8-4457-be92-24b18a0743fc",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.isPrivate }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "337b4eb0-d906-4afb-9de0-8864070d3b86",
      "name": "Respond Private IP Ignored",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        960,
        0
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "{\n  \"status\": \"ignored\",\n  \"message\": \"Private or internal IP address\",\n  \"ip\": \"{{ $json.ip }}\"\n}\n"
      },
      "typeVersion": 1.5
    },
    {
      "id": "cae185f7-875f-450e-a92e-43a1cf68e060",
      "name": "Enrich IP (Geo & ASN Lookup)",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1200,
        128
      ],
      "parameters": {
        "url": "=https://ipinfo.io/{{ $json.ip }}/json",
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "44c3efcd-5d76-4314-b818-ef7a086a4524",
      "name": "Normalize Enrichment",
      "type": "n8n-nodes-base.code",
      "position": [
        1440,
        128
      ],
      "parameters": {
        "jsCode": "const data = $json;\n\n// High-risk country list (adjust as needed)\nconst highRiskCountries = [\"RU\", \"CN\", \"IR\", \"KP\"];\n\n// Determine severity\nconst severity = highRiskCountries.includes(data.country)\n  ? \"\ud83d\udea8 HIGH RISK\"\n  : \"\ud83d\udfe2 Normal\";\n\nreturn [{\n  json: {\n    ip: data.ip,\n    country: data.country || \"Unknown\",\n    region: data.region || \"Unknown\",\n    city: data.city || \"Unknown\",\n    isp: data.org || \"Unknown\",\n    asn: data.org?.split(\" \")[0] || \"N/A\",\n    severity\n  }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "49f8d9f9-9f57-4fa5-956d-e03eb6fe1ae6",
      "name": "Slack Alert: IP Enrichment Result",
      "type": "n8n-nodes-base.slack",
      "position": [
        1664,
        128
      ],
      "parameters": {
        "text": "=\ud83d\udd0d *IP Enrichment Result*\n\n\u2022 *IP:* {{$json.ip}}\n\u2022 *Country:* {{$json.country}}\n\u2022 *Region:* {{$json.region}}\n\u2022 *City:* {{$json.city}}\n\u2022 *ISP / Org:* {{$json.isp}}\n\u2022 *ASN:* {{$json.asn}}\n\n\n",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C0A252GLT70",
          "cachedResultName": "all-team-sawi"
        },
        "otherOptions": {
          "includeLinkToWorkflow": false
        }
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.4
    },
    {
      "id": "4528ebd2-bdf9-4d7d-b670-b7c0f4b078a7",
      "name": "Respond IP Enrichment Result",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1904,
        128
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "{\n  \"status\": \"success\",\n  \"ip\": \"{{ $json.ip }}\",\n  \"country\": \"{{ $json.country }}\",\n  \"region\": \"{{ $json.region }}\",\n  \"city\": \"{{ $json.city }}\",\n  \"isp\": \"{{ $json.isp }}\",\n  \"asn\": \"{{ $json.asn }}\"\n}\n"
      },
      "typeVersion": 1.5
    },
    {
      "id": "458cea81-a568-4066-b0ff-4ce305d40704",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -64,
        -80
      ],
      "parameters": {
        "color": 7,
        "width": 656,
        "height": 480,
        "content": "## 1. Input & Validation"
      },
      "typeVersion": 1
    },
    {
      "id": "43b94590-d6ce-4c97-a616-b260a75b5145",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        608,
        -80
      ],
      "parameters": {
        "color": 7,
        "width": 496,
        "height": 480,
        "content": "## 2. Private IP Handling"
      },
      "typeVersion": 1
    },
    {
      "id": "387ea9c6-156e-42c7-948d-e3e9d231999f",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1120,
        -80
      ],
      "parameters": {
        "color": 7,
        "height": 480,
        "content": "## IP Enrichment"
      },
      "typeVersion": 1
    },
    {
      "id": "5cd807b5-9d24-4a68-9bf5-5d7d2a977644",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1376,
        -80
      ],
      "parameters": {
        "color": 7,
        "width": 224,
        "height": 480,
        "content": "## Normalization & Severity"
      },
      "typeVersion": 1
    },
    {
      "id": "c93ba500-996d-4ca7-b812-a1b75863af09",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1616,
        -80
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 480,
        "content": "## Output & Notification"
      },
      "typeVersion": 1
    },
    {
      "id": "be5342d4-8614-438a-a556-9f4c3d2ff977",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -576,
        -272
      ],
      "parameters": {
        "width": 416,
        "height": 768,
        "content": "## I'm a note \nIP Enrichment & Attribution is a lightweight cybersecurity automation designed to enrich IP addresses with geographic and network intelligence. It helps security teams, SOC analysts, and automation builders quickly understand where an IP comes from, who owns it, and whether it should be treated as potentially risky.\n\n## How it works\n1. Receives an **IP address** via webhook (**API** or **Slack**).\n2. Validates the IP format and **rejects invalid input**.\n3. Checks for **private** or **internal IP** ranges.\n4. Ignores private IPs wit a clear respons.\n5. Enriches public IPs using an **open-source IP intelligence** service.\n6. Normalizes **county**, **ISP**, and **ASN** data and applies a **severity**  label.\n7. Sends results to Slack and returns a **structured JSON response**.\n\n## Setup steps\n1. Import the workflow into your n8n instance\n2. Activate the workflow\n3. Configure **Slack credentials** and select a target channel\n4. Send a **POST** request with an **IP address** to the webhook URL\n\n## Customization\n1. Extend workflow by adding reputation scores.\n2. Country risk logic\n3. SIEM Integratons"
      },
      "typeVersion": 1
    }
  ],
  "active": true,
  "settings": {
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "dc334627-5066-4a08-9973-7171cbb91391",
  "connections": {
    "If IP is Valid": {
      "main": [
        [
          {
            "node": "Check Private / Internal IP",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond Invalid IP Address",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If IP is Private": {
      "main": [
        [
          {
            "node": "Respond Private IP Ignored",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Enrich IP (Geo & ASN Lookup)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate IP Address": {
      "main": [
        [
          {
            "node": "If IP is Valid",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Enrichment": {
      "main": [
        [
          {
            "node": "Slack Alert: IP Enrichment Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Private / Internal IP": {
      "main": [
        [
          {
            "node": "If IP is Private",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Weebhook - Receive IP Input": {
      "main": [
        [
          {
            "node": "Validate IP Address",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Enrich IP (Geo & ASN Lookup)": {
      "main": [
        [
          {
            "node": "Normalize Enrichment",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Respond IP Enrichment Result": {
      "main": [
        []
      ]
    },
    "Slack Alert: IP Enrichment Result": {
      "main": [
        [
          {
            "node": "Respond IP Enrichment Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}