{
  "id": "U6vIbCR5FD9EuQl4",
  "meta": {
    "builderVariant": "mcp",
    "aiBuilderAssisted": true
  },
  "name": "Scam Site Forensic Investigator",
  "tags": [],
  "nodes": [
    {
      "id": "a40bffd4-43d4-4900-9a73-4eedfccbc1ed",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1184,
        -352
      ],
      "parameters": {
        "width": 480,
        "height": 896,
        "content": "## Scam Site Forensic Investigator\n\n### How it works\n\nThis workflow investigates a user-submitted suspicious URL by extracting its domain and running several parallel enrichment checks. It gathers registration, certificate, DNS, hosting, URLScan.io, and live HTML fingerprint data, then merges the findings into a consolidated forensic case. It compares the new indicators against historical case logs and produces outputs for alerting, archiving, and abuse-report follow-up.\n\n### Setup steps\n\n- Configure the form trigger so it captures the submitted scam URL in the field expected by the Extract Domain and Fetch Scam Page HTML nodes.\n- Add a URLScan.io API key to the Submit to URLScan.io request headers and confirm the wait duration is long enough for scans to finish.\n- Set up the data table used for the case log with columns matching the consolidation and correlation code nodes.\n- Configure Telegram credentials, bot, and target chat for the Send Telegram Report node.\n- Configure Gmail credentials and recipient/draft settings for the Draft Abuse Report Email node.\n- Review any HTTP request rate limits or optional API credentials for IPInfo and other enrichment services.\n\n### Customization\n\nYou can adjust the fingerprint extraction and correlation code to look for additional scam-kit markers, wallet addresses, tracking IDs, brand impersonation signals, or infrastructure overlaps. Report formatting, Telegram destination, case log schema, and abuse email templates can also be tailored to an investigation team's workflow."
      },
      "typeVersion": 1
    },
    {
      "id": "1cf1773b-6ff4-42ce-9da4-d72e38b30b80",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1744,
        48
      ],
      "parameters": {
        "color": 7,
        "width": 464,
        "height": 320,
        "content": "## Submit and parse URL\n\nReceives the suspected scam URL from a form and extracts the normalized domain used by all investigation branches."
      },
      "typeVersion": 1
    },
    {
      "id": "2725a695-7a97-4be5-9d07-cadb325ae613",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2272,
        -352
      ],
      "parameters": {
        "color": 7,
        "height": 576,
        "content": "## Domain registration intel\n\nQueries public domain intelligence sources for RDAP registration data and certificate transparency records related to the submitted domain."
      },
      "typeVersion": 1
    },
    {
      "id": "a735710a-6fdd-4b85-bc13-76804239c251",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2272,
        256
      ],
      "parameters": {
        "color": 7,
        "width": 704,
        "height": 304,
        "content": "## DNS and hosting lookup\n\nResolves the domain to an A record, extracts the IP address, and retrieves hosting and network details for that IP."
      },
      "typeVersion": 1
    },
    {
      "id": "778c3fd1-5309-485c-8731-f5956e4f67a3",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2272,
        592
      ],
      "parameters": {
        "color": 7,
        "width": 704,
        "height": 304,
        "content": "## URLScan sandbox scan\n\nSubmits the suspicious URL to URLScan.io, waits for analysis to complete, and fetches the resulting scan data."
      },
      "typeVersion": 1
    },
    {
      "id": "f0546d66-cab0-413e-a4da-903e7189b61b",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2272,
        928
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 320,
        "content": "## HTML fingerprint extraction\n\nFetches the live scam page HTML and extracts forensic fingerprints such as page artifacts, indicators, or reusable patterns."
      },
      "typeVersion": 1
    },
    {
      "id": "fa1d04a5-de11-4938-a28c-559f6c7e6dcb",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3056,
        48
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 416,
        "content": "## Merge investigation findings\n\nCollects all enrichment branches into a single stream and consolidates their results into a unified case finding object."
      },
      "typeVersion": 1
    },
    {
      "id": "c01e6c14-6516-4377-99fa-05de15094de3",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3568,
        32
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 336,
        "content": "## Correlate with history\n\nLoads existing case log rows and compares the new site's fingerprints against prior investigations to identify shared infrastructure or repeated scam kits."
      },
      "typeVersion": 1
    },
    {
      "id": "aa7afb50-a4ad-47eb-a89e-2c694385444c",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4096,
        -96
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 624,
        "content": "## Report and archive case\n\nFormats the investigation report, sends it to Telegram, stores the case in the log, and drafts an abuse report email for follow-up action."
      },
      "typeVersion": 1
    },
    {
      "id": "47b7f88d-3376-41d7-a1b9-ffc07bee37dc",
      "name": "When URL Submitted",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        1792,
        208
      ],
      "parameters": {
        "options": {
          "respondWithOptions": {
            "values": {
              "formSubmittedText": "Investigation started. Check your configured Telegram chat for the report."
            }
          }
        },
        "formTitle": "Scam Site Investigator",
        "formFields": {
          "values": [
            {
              "fieldName": "scamUrl",
              "fieldLabel": "Scam URL",
              "placeholder": "https://suspicious-site.example",
              "requiredField": true
            }
          ]
        },
        "formDescription": "Submit a suspected scam or phishing URL to run a forensic investigation and look for links to other scam infrastructure."
      },
      "typeVersion": 2.6
    },
    {
      "id": "f33beae7-ede3-46cb-830b-49ec5b9e7850",
      "name": "Parse Domain from URL",
      "type": "n8n-nodes-base.code",
      "position": [
        2064,
        208
      ],
      "parameters": {
        "jsCode": "const first = $input.first().json;\nconst rawInput = first['Scam URL'] || first.scamUrl || first.url || '';\nlet urlStr = String(rawInput).trim();\nif (!/^https?:\\/\\//i.test(urlStr)) { urlStr = 'http://' + urlStr; }\nlet domain = '';\ntry {\n  domain = new URL(urlStr).hostname.replace(/^www\\./, '');\n} catch (e) {\n  domain = urlStr.replace(/^https?:\\/\\//i, '').split('/')[0].replace(/^www\\./, '');\n}\nreturn [{ json: { submittedUrl: urlStr, domain } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "998960e3-b8fe-4af6-9e06-4753ff951aa3",
      "name": "Fetch RDAP Domain Info",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2320,
        -96
      ],
      "parameters": {
        "url": "=https://rdap.org/domain/{{ $json.domain }}",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "f34281d9-dad2-4406-970e-3ff74c81c3db",
      "name": "Merge Enrichment Data",
      "type": "n8n-nodes-base.merge",
      "position": [
        3104,
        208
      ],
      "parameters": {
        "numberInputs": 5
      },
      "typeVersion": 3.2
    },
    {
      "id": "85dac1f1-7bf6-494d-9a81-981ab0691bd3",
      "name": "Fetch Certificate Transparency Info",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2320,
        64
      ],
      "parameters": {
        "url": "=https://crt.sh/?q={{ $json.domain }}&output=json",
        "options": {
          "response": {
            "response": {
              "neverError": true,
              "responseFormat": "text",
              "outputPropertyName": "rawCertData"
            }
          }
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "a699bb3d-deca-4632-9fcd-de29b6e3b276",
      "name": "Fetch DNS A Record",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2320,
        384
      ],
      "parameters": {
        "url": "=https://dns.google/resolve?name={{ $json.domain }}&type=A",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "847f1ef3-55fd-460e-99ff-f6de1efa69e6",
      "name": "Parse Resolved IP",
      "type": "n8n-nodes-base.code",
      "position": [
        2576,
        384
      ],
      "parameters": {
        "jsCode": "const item = $input.first().json;\nconst answers = item.Answer || [];\nconst aRecord = answers.find(a => a.type === 1);\nreturn [{ json: { ip: aRecord ? aRecord.data : null } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "202d6aee-b902-46c4-acce-8b3f4b5535f9",
      "name": "Fetch IP Hosting Info",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2832,
        384
      ],
      "parameters": {
        "url": "=https://ipinfo.io/{{ $json.ip }}/json",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "723c1c8c-13a9-400c-a80d-f8db573cce7f",
      "name": "Submit for URLScan.io Analysis",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2320,
        720
      ],
      "parameters": {
        "url": "https://urlscan.io/api/v1/scan/",
        "method": "POST",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        },
        "jsonBody": "={{ { \"url\": $json.submittedUrl, \"visibility\": \"unlisted\" } }}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "typeVersion": 4.4
    },
    {
      "id": "accde85d-b159-4975-a3a1-d99d394a1275",
      "name": "Wait 15 Seconds for Scan",
      "type": "n8n-nodes-base.wait",
      "position": [
        2576,
        720
      ],
      "parameters": {
        "amount": 15
      },
      "typeVersion": 1.1
    },
    {
      "id": "4f4b6d2b-7275-41ef-9608-ecc1c8d1265c",
      "name": "Fetch URLScan.io Results",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2832,
        720
      ],
      "parameters": {
        "url": "=https://urlscan.io/api/v1/result/{{ $json.uuid }}/",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        },
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "typeVersion": 4.4
    },
    {
      "id": "9ad72d38-9a1d-491a-a7ed-9ac75575612f",
      "name": "Fetch HTML of Scam Page",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        2320,
        1088
      ],
      "parameters": {
        "url": "={{ $json.submittedUrl }}",
        "options": {
          "response": {
            "response": {
              "neverError": true,
              "responseFormat": "text",
              "outputPropertyName": "html"
            }
          }
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "a9a7a518-dcf5-406b-9799-7142ca7d6e35",
      "name": "Parse HTML Fingerprints",
      "type": "n8n-nodes-base.code",
      "position": [
        2576,
        1088
      ],
      "parameters": {
        "jsCode": "const html = ($input.first().json.html) || '';\nconst gaMatch = html.match(/\\b(UA-\\d{4,10}-\\d{1,4}|G-[A-Z0-9]{6,12})\\b/);\nconst fbPixelMatch = html.match(/fbq\\(['\"]init['\"],\\s*['\"](\\d{10,20})['\"]/);\nconst adsenseMatch = html.match(/\\bpub-\\d{10,20}\\b/);\nconst faviconMatch = html.match(/<link[^>]+rel=[\"'](?:shortcut )?icon[\"'][^>]+href=[\"']([^\"']+)[\"']/i);\nconst btcMatch = html.match(/\\b(bc1[a-z0-9]{25,39}|[13][a-km-zA-HJ-NP-Z1-9]{25,34})\\b/);\nconst ethMatch = html.match(/\\b0x[a-fA-F0-9]{40}\\b/);\nconst telegramMatch = html.match(/t\\.me\\/[a-zA-Z0-9_]{5,32}/);\nreturn [{ json: {\n  gaOrPixelId: gaMatch ? gaMatch[0] : null,\n  fbPixelId: fbPixelMatch ? fbPixelMatch[1] : null,\n  adsenseId: adsenseMatch ? adsenseMatch[0] : null,\n  faviconUrl: faviconMatch ? faviconMatch[1] : null,\n  btcWallet: btcMatch ? btcMatch[0] : null,\n  ethWallet: ethMatch ? ethMatch[0] : null,\n  telegramContact: telegramMatch ? telegramMatch[0] : null\n} }];"
      },
      "typeVersion": 2
    },
    {
      "id": "8fbf22d6-1d51-4303-aab4-70c01fc8296e",
      "name": "Combine All Findings",
      "type": "n8n-nodes-base.code",
      "position": [
        3360,
        208
      ],
      "parameters": {
        "jsCode": "const domainInfo = $('Parse Domain from URL').first().json;\nconst rdap = $('Fetch RDAP Domain Info').first().json || {};\nconst ipInfoData = $('Fetch IP Hosting Info').first().json || {};\nconst scanResult = $('Fetch URLScan.io Results').first().json || {};\nconst fingerprints = $('Parse HTML Fingerprints').first().json || {};\nlet crtEntries = [];\ntry {\n  const raw = $('Fetch Certificate Transparency Info').first().json.rawCertData || '[]';\n  crtEntries = JSON.parse(raw);\n} catch (e) { crtEntries = []; }\nconst relatedDomainsFromCert = [...new Set(crtEntries.flatMap(c => (c.name_value || '').split('\\n')))].filter(d => d && d !== domainInfo.domain);\nconst regEvent = (rdap.events || []).find(e => e.eventAction === 'registration');\nreturn [{ json: {\n  domain: domainInfo.domain,\n  submittedUrl: domainInfo.submittedUrl,\n  registrar: rdap.handle || (rdap.port43 || 'unknown'),\n  domainCreated: regEvent ? regEvent.eventDate : null,\n  relatedDomainsFromCert,\n  ip: ipInfoData.ip || null,\n  hostingOrg: ipInfoData.org || null,\n  hostingCity: ipInfoData.city || null,\n  hostingCountry: ipInfoData.country || null,\n  abuseContact: (ipInfoData.abuse && ipInfoData.abuse.address) || null,\n  gaOrPixelId: fingerprints.gaOrPixelId || null,\n  fbPixelId: fingerprints.fbPixelId || null,\n  adsenseId: fingerprints.adsenseId || null,\n  faviconUrl: fingerprints.faviconUrl || null,\n  btcWallet: fingerprints.btcWallet || null,\n  ethWallet: fingerprints.ethWallet || null,\n  telegramContact: fingerprints.telegramContact || null,\n  urlscanReportUrl: (scanResult.task && scanResult.task.uuid) ? ('https://urlscan.io/result/' + scanResult.task.uuid + '/') : null,\n  investigatedAt: new Date().toISOString()\n} }];"
      },
      "typeVersion": 2
    },
    {
      "id": "744ac32a-019d-4e3f-824f-a319a50d36a3",
      "name": "Retrieve Case Logs",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        3616,
        208
      ],
      "parameters": {
        "operation": "get",
        "returnAll": true,
        "dataTableId": {
          "__rl": true,
          "mode": "name",
          "value": "Scam Site Case Log"
        }
      },
      "typeVersion": 1.1,
      "alwaysOutputData": true
    },
    {
      "id": "1cd1a01b-5bb6-4a95-a091-0cce050b0f2f",
      "name": "Analyze Fingerprint Correlations",
      "type": "n8n-nodes-base.code",
      "position": [
        3872,
        208
      ],
      "parameters": {
        "jsCode": "const current = $('Combine All Findings').first().json;\nconst priorRows = $input.all().map(i => i.json);\nconst fingerprintFields = ['gaOrPixelId', 'fbPixelId', 'adsenseId', 'faviconUrl', 'btcWallet', 'ethWallet', 'telegramContact'];\nconst relatedCases = [];\nfor (const row of priorRows) {\n  if (!row || row.domain === current.domain) continue;\n  const matches = fingerprintFields.filter(f => current[f] && row[f] && current[f] === row[f]);\n  if (matches.length > 0) { relatedCases.push({ domain: row.domain, matchedOn: matches, investigatedAt: row.investigatedAt }); }\n}\nreturn [{ json: Object.assign({}, current, { relatedCases }) }];"
      },
      "typeVersion": 2
    },
    {
      "id": "66a37f57-7f29-48cd-8d1f-8f6687391a01",
      "name": "Prepare Report Format",
      "type": "n8n-nodes-base.code",
      "position": [
        4144,
        64
      ],
      "parameters": {
        "jsCode": "const r = $input.first().json;\nconst related = (r.relatedCases && r.relatedCases.length) ? ('\\n\\nLinked to ' + r.relatedCases.length + ' prior case(s):\\n' + r.relatedCases.map(c => '- ' + c.domain + ' (matched: ' + c.matchedOn.join(', ') + ')').join('\\n')) : '';\nconst certRelated = (r.relatedDomainsFromCert && r.relatedDomainsFromCert.length) ? ('\\n\\nDomains sharing a TLS certificate:\\n' + r.relatedDomainsFromCert.slice(0, 10).map(d => '- ' + d).join('\\n')) : '';\nconst text = 'Scam Site Investigation: ' + r.domain + '\\n\\n' +\n  'URL: ' + r.submittedUrl + '\\n' +\n  'Registrar: ' + (r.registrar || 'unknown') + '\\n' +\n  'Domain created: ' + (r.domainCreated || 'unknown') + '\\n' +\n  'Hosting: ' + (r.hostingOrg || 'unknown') + ' (' + (r.hostingCity || '?') + ', ' + (r.hostingCountry || '?') + ')\\n' +\n  'Server IP: ' + (r.ip || 'unknown') + '\\n' +\n  'Abuse contact: ' + (r.abuseContact || 'not published') + '\\n' +\n  'Analytics/Pixel ID: ' + (r.gaOrPixelId || r.fbPixelId || r.adsenseId || 'none found') + '\\n' +\n  'Wallets found: ' + ([r.btcWallet, r.ethWallet].filter(Boolean).join(', ') || 'none') + '\\n' +\n  'Telegram contact: ' + (r.telegramContact || 'none') + '\\n' +\n  'Full scan report: ' + (r.urlscanReportUrl || 'n/a') + certRelated + related;\nreturn [{ json: { reportText: text } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "5c70a018-cf3b-4c13-aac4-dea6e0faab90",
      "name": "Dispatch Telegram Report",
      "type": "n8n-nodes-base.telegram",
      "position": [
        4400,
        64
      ],
      "parameters": {
        "text": "={{ $json.reportText }}",
        "chatId": "placeholder",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "c79d5a1a-e260-429b-9757-f9b70ec1d865",
      "name": "Log Case Data",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        4144,
        208
      ],
      "parameters": {
        "columns": {
          "value": {
            "ip": "={{ $json.ip }}",
            "domain": "={{ $json.domain }}",
            "adsenseId": "={{ $json.adsenseId }}",
            "btcWallet": "={{ $json.btcWallet }}",
            "ethWallet": "={{ $json.ethWallet }}",
            "fbPixelId": "={{ $json.fbPixelId }}",
            "registrar": "={{ $json.registrar }}",
            "faviconUrl": "={{ $json.faviconUrl }}",
            "hostingOrg": "={{ $json.hostingOrg }}",
            "gaOrPixelId": "={{ $json.gaOrPixelId }}",
            "hostingCity": "={{ $json.hostingCity }}",
            "abuseContact": "={{ $json.abuseContact }}",
            "domainCreated": "={{ $json.domainCreated }}",
            "hostingCountry": "={{ $json.hostingCountry }}",
            "investigatedAt": "={{ $json.investigatedAt }}",
            "telegramContact": "={{ $json.telegramContact }}",
            "urlscanReportUrl": "={{ $json.urlscanReportUrl }}",
            "relatedDomainsFromCert": "={{ JSON.stringify($json.relatedDomainsFromCert) }}"
          },
          "mappingMode": "defineBelow"
        },
        "filters": {
          "conditions": [
            {
              "keyName": "domain",
              "keyValue": "={{ $json.domain }}"
            }
          ]
        },
        "options": {},
        "operation": "upsert",
        "dataTableId": {
          "__rl": true,
          "mode": "name",
          "value": "Scam Site Case Log"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "e29b94a3-8ff0-47a1-bd2b-9273690c7d01",
      "name": "Compose Abuse Report Email",
      "type": "n8n-nodes-base.gmail",
      "position": [
        4144,
        368
      ],
      "parameters": {
        "message": "=Hello,\n\nThis is a report of suspected phishing/scam content hosted on your infrastructure.\n\nURL: {{ $json.submittedUrl }}\nDomain: {{ $json.domain }}\nServer IP: {{ $json.ip }}\nRegistrar: {{ $json.registrar }}\nDetected: {{ $json.investigatedAt }}\nFull technical report: {{ $json.urlscanReportUrl }}\n\nPlease investigate and take appropriate action.\n\nThis draft was generated automatically and held for manual review before sending.",
        "options": {
          "sendTo": "={{ $json.abuseContact }}"
        },
        "subject": "=Abuse Report: Suspected Phishing/Scam Content at {{ $json.domain }}",
        "resource": "draft"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": true,
    "executionOrder": "v1"
  },
  "versionId": "659c64e7-e5c3-49ab-ab22-93760b45eb57",
  "nodeGroups": [],
  "connections": {
    "Parse Resolved IP": {
      "main": [
        [
          {
            "node": "Fetch IP Hosting Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch DNS A Record": {
      "main": [
        [
          {
            "node": "Parse Resolved IP",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Retrieve Case Logs": {
      "main": [
        [
          {
            "node": "Analyze Fingerprint Correlations",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When URL Submitted": {
      "main": [
        [
          {
            "node": "Parse Domain from URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Combine All Findings": {
      "main": [
        [
          {
            "node": "Retrieve Case Logs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch IP Hosting Info": {
      "main": [
        [
          {
            "node": "Merge Enrichment Data",
            "type": "main",
            "index": 2
          }
        ]
      ]
    },
    "Merge Enrichment Data": {
      "main": [
        [
          {
            "node": "Combine All Findings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Domain from URL": {
      "main": [
        [
          {
            "node": "Fetch RDAP Domain Info",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch Certificate Transparency Info",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch DNS A Record",
            "type": "main",
            "index": 0
          },
          {
            "node": "Submit for URLScan.io Analysis",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch HTML of Scam Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Report Format": {
      "main": [
        [
          {
            "node": "Dispatch Telegram Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch RDAP Domain Info": {
      "main": [
        [
          {
            "node": "Merge Enrichment Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch HTML of Scam Page": {
      "main": [
        [
          {
            "node": "Parse HTML Fingerprints",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse HTML Fingerprints": {
      "main": [
        [
          {
            "node": "Merge Enrichment Data",
            "type": "main",
            "index": 4
          }
        ]
      ]
    },
    "Fetch URLScan.io Results": {
      "main": [
        [
          {
            "node": "Merge Enrichment Data",
            "type": "main",
            "index": 3
          }
        ]
      ]
    },
    "Wait 15 Seconds for Scan": {
      "main": [
        [
          {
            "node": "Fetch URLScan.io Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Submit for URLScan.io Analysis": {
      "main": [
        [
          {
            "node": "Wait 15 Seconds for Scan",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Analyze Fingerprint Correlations": {
      "main": [
        [
          {
            "node": "Prepare Report Format",
            "type": "main",
            "index": 0
          },
          {
            "node": "Log Case Data",
            "type": "main",
            "index": 0
          },
          {
            "node": "Compose Abuse Report Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Certificate Transparency Info": {
      "main": [
        [
          {
            "node": "Merge Enrichment Data",
            "type": "main",
            "index": 1
          }
        ]
      ]
    }
  }
}