# Chrome-to-n8n — BLOG 2 Intelligence

A Chrome extension and n8n workflow that ingests threat intelligence blog posts, automatically extracts defanged IOCs, and creates fully attributed MISP events with typed indicators and auto-derived tags.

## Components

### Chrome Extension — "Page to Webhook"

A Manifest V3 browser extension that captures the current page and POSTs it to a configurable webhook endpoint.

**What it sends:**

```json
{
  "url": "https://blog.example.com/threat-report",
  "title": "New Phishing Campaign Analysis",
  "timestamp": "2026-03-16T12:00:00.000Z",
  "content": "Full visible page text (optional)"
}
```

An example blog post used during R&D: https://newtonpaul.com/blog/device-code-phishing-campaign/

**Files:**
- `manifest.json` — Extension manifest (MV3, requires `activeTab`, `storage`, `scripting`, `host_permissions`)
- `popup.html` / `popup.js` — Popup UI with send button and content toggle
- `options.html` / `options.js` — Settings page to configure the webhook URL
- `background.js` — Service worker that performs the POST (bypasses CORS)
- `icons/` — Extension icons

**Installation:**
1. Open `chrome://extensions`
2. Enable **Developer mode**
3. Click **Load unpacked** → select this folder
4. Click the extension icon → **Set it up** → paste your n8n webhook URL → Save

### n8n Workflow — "BLOG 2 Intelligence"

![Workflow Preview](preview.png "Workflow Preview")


#### Flow

```
Webhook
  → Extract IOCs (Code)
    → Create MISP Event
      → Prepare Attributes (Code)
        → Loop Over Items
          → Tag Check (IF: type == __event_tags__)
            ├─ TRUE:  Separate Tags → Loop Tags → Create Tag → Add Tag to Event
            └─ FALSE: Add Attribute to MISP
```

#### Node Descriptions

| # | Node | Purpose |
|---|---|---|
| 1 | **Webhook** | Receives POST from the Chrome extension with URL, title, and page content |
| 2 | **Extract IOCs** | Parses article text for defanged indicators: domains (`[.]`), emails (`[@]`), URLs (`hxxp`), SHA256/SHA1/MD5 hashes, IPv4 addresses. Refangs all values. Deduplicates and filters hash substrings |
| 3 | **Create MISP Event** | Creates a MISP event titled `"{article title} - {source URL}"` with threat level Medium, distribution Org Only, analysis Initial |
| 4 | **Prepare Attributes** | Transforms extracted data into MISP-ready items with proper types. Derives event tags from content keywords. Outputs a flat array including a `__event_tags__` sentinel item |
| 5 | **Loop Over Items** | SplitInBatches iterator — processes one item at a time |
| 6 | **Tag Check** | IF node — routes `__event_tags__` items to the tag path, everything else to the attribute path |
| 7 | **Add Attribute to MISP** | Creates each MISP attribute on the event using expression-based types (bypasses the UI dropdown limitation) |
| 8 | **Separate Tags** | Explodes the tags array into individual `{eventId, tag}` items |
| 9 | **Loop Tags** | Inner SplitInBatches — iterates through each tag |
| 10 | **Create Tag** | Ensures the tag exists in MISP (idempotent) |
| 11 | **Add Tag to Event** | Attaches the tag to the MISP event |

#### IOC Types Extracted

| Pattern | MISP Type | Category |
|---|---|---|
| `example[.]com` | `domain` | Network activity |
| `user[@]domain[.]com` | `email-src` | Payload delivery |
| `hxxps://example[.]com/path` | `url` | Network activity |
| 64-char hex string | `sha256` | Payload delivery |
| 40-char hex string | `sha1` | Payload delivery |
| 32-char hex string | `md5` | Payload delivery |
| Public IPv4 address | `ip-dst` | Network activity |

Additionally, each event gets:
- `link` — original article URL (External analysis)
- `comment` — article context: title, URL, ingest timestamp (External analysis)
- `text` — full article content (External analysis)

#### Auto-Derived Tags

Tags are derived by keyword matching against the article content:

| Keyword | Tag |
|---|---|
| "phishing" | `phishing`, `misp-galaxy:attack-pattern="Phishing - T1566"` |
| "device code" | `device-code-phishing` |
| "token theft" / "refresh token" | `token-theft`, `misp-galaxy:attack-pattern="Steal Application Access Token - T1528"` |
| "workers.dev" / "cloudflare worker" | `cloudflare-workers` |
| "business email compromise" | `bec`, `misp-galaxy:attack-pattern="Business Email Compromise - T1534"` |
| "ransomware" | `ransomware` |
| "malware" | `malware` |
| "command and control" | `c2` |
| *(always applied)* | `tlp:clear`, `workflow:automated-enrichment` |

#### Credentials Required

| Credential | Type | Used By |
|---|---|---|
| MISP Docker | `mispApi` | Create MISP Event, Add Attribute, Create Tag, Add Tag to Event |

## Design Decisions

- **Defanged IOCs only:** Extraction targets defanged notation (`[.]`, `[@]`, `hxxp`) which is standard practice in threat intel blogs. Non-defanged indicators are intentionally skipped to avoid noise from navigation links, CDN hostnames, and boilerplate page content.
- **CORS bypass:** The Chrome extension routes fetch requests through a background service worker, which is not subject to browser CORS restrictions. This avoids requiring CORS configuration on the n8n/webhook side.
- **Expression-based MISP types:** The n8n MISP node's attribute type dropdown only exposes `text`, `url`, and `comment`. By using expressions (`={{ $json.type }}`), any valid MISP attribute type can be passed through to the API.
- **`__event_tags__` sentinel pattern:** Borrowed from the reference workflow (Firewall Alert URL IOC Enrichment). A sentinel item type is used to route tag items through a separate processing path within the same loop, keeping the workflow clean.
- **Hash substring dedup:** SHA1 matches are checked against existing SHA256 values, and MD5 matches against both, to avoid extracting substrings of longer hashes as false positives.
