SIEM integration (OCSF / CEF)
Stream findings and DNS changes to Splunk, Microsoft Sentinel, Google SecOps, QRadar, ArcSight or any collector as Open Cybersecurity Schema Framework (OCSF) events or Common Event Format (CEF) lines, batched and retried.
DNS Watchdog can feed your SIEM directly. A SIEM (OCSF / CEF) notification channel emits every finding and every DNS change as an Open Cybersecurity Schema Framework event — the vendor-neutral schema that Splunk, Microsoft Sentinel, Google SecOps (Chronicle), Amazon Security Lake and most modern pipelines ingest natively — or, for collectors that expect it, as an ArcSight Common Event Format (CEF) line. Either way, findings land in the tools your security operation already runs, without a custom parser.
Compared with a custom webhook, a SIEM channel:
- sends every change, not a top-20 summary;
- uses industry schema (OCSF
Detection Finding,Entity ManagementandScan Activityclasses) rather than a product-specific payload; - is batched (up to 100 events per request) and retried durably — a collector outage delays delivery, it does not lose a finding;
- supports the wire formats collectors expect: a JSON array, NDJSON, Splunk HTTP Event Collector envelopes, or CEF lines;
- carries an optional credential header, stored encrypted.
Setting up a channel
- In your SIEM, create an HTTPS ingestion endpoint and (usually) a token — see Per-SIEM notes.
- In DNS Watchdog, go to Settings → Notifications, click Add notification and choose SIEM (OCSF / CEF).
- Fill in the form:
| Field | What to enter |
|---|---|
| Label | A name for the channel, e.g. Splunk (SOC) |
| Collector URL | The HTTPS endpoint your SIEM ingests on. Stored encrypted and never shown again |
| Format | JSON array (default), NDJSON, Splunk HEC or CEF — see Wire formats |
| Events to send | Findings, DNS changes and scan summaries (default) or Findings only |
| Auth header name | The header the credential is sent in. Defaults to Authorization; some collectors want their own, e.g. X-goog-api-key |
| Credential | Optional. The token to send in that header, stored encrypted. Leave empty if the collector authenticates by URL or network |
- Click Add SIEM Integration, then click Test. The test posts a single, clearly labelled OCSF event (
class_uid6007,activity_nameConnectivity Test,metadata.labels: ["test"]; as a CEF line it carries the signaturesiem.testandcs6=test) through the same URL, format and credential a real batch uses, so a green test means real batches will arrive.
Creating, updating and deleting channels requires the Admin or Member role. Deleting the channel removes the URL and credential from encrypted storage.
Wire formats
| Format | Request body | Content-Type | Use with |
|---|---|---|---|
| JSON array | [ {event}, {event}, … ] | application/json | Microsoft Sentinel Logs Ingestion, Google SecOps webhook feeds, Cribl Stream, Vector, Fluent Bit, Amazon Security Lake custom sources, your own collector |
| NDJSON | One event per line | application/x-ndjson | Collectors that read newline-delimited JSON |
| Splunk HEC | Concatenated HEC envelopes: {"time": …, "source": "dnswatchdog", "event": {event}} | application/json | Splunk HTTP Event Collector (/services/collector/event) |
| CEF | One Common Event Format line per event, newline-terminated | text/plain; charset=utf-8 | Splunk HEC raw endpoint (/services/collector/raw), IBM QRadar HTTP Receiver, ArcSight, Microsoft Sentinel behind a CEF forwarder, Cribl Stream, Logstash |
Every request also carries User-Agent: DNS-Watchdog-SIEM/1.0.
For Splunk HEC the credential is your HEC token; DNS Watchdog adds the Splunk scheme to the Authorization header if you paste the bare token. No sourcetype is set in the envelope, so the token's default sourcetype applies — set it on the token to route and parse events as you prefer.
CEF
Choose CEF for a collector that ingests ArcSight Common Event Format rather than JSON. Every event becomes one line, newline-terminated:
CEF:0|dnswatchdog.io|DNS Watchdog|20260901.1|issue_detected|Port 3389 Open (RDP) detected on rdp.example.com|8|rt=1777342530000 externalId=c2f1… cat=Detection Finding act=Create outcome=New dhost=rdp.example.com dst=203.0.113.5 dpt=3389 cs1Label=tenantId cs1=org_abc123 cs2Label=zone cs2=example.com cs3Label=issueType cs3=port_open_rdp cs4Label=scanId cs4=… cs5Label=changelogUrl cs5=https://app.dnswatchdog.io/audit/changes?scan_id\=… cs6Label=labels cs6=scan_type:daily_scan cn1Label=ocsfClassUid cn1=2004 cn2Label=ocsfTypeUid cn2=200401 flexString1Label=scanType flexString1=daily_scanThe header is CEF:0|Device Vendor|Device Product|Device Version|Signature ID|Name|Severity|:
| Header field | Value |
|---|---|
| Device Vendor / Product / Version | dnswatchdog.io, DNS Watchdog, the DNS Watchdog release |
| Signature ID | The DNS Watchdog change type: issue_detected, issue_resolved, issue_ignored, issue_note_added, record_detected, record_changed, record_deleted, record_removed_externally, zone_detected, zone_removed, provider_removed or scan.completed; the test event carries siem.test |
| Name | The event's one-line summary (the OCSF message) |
| Severity | The OCSF severity on CEF's 0–10 scale: Unknown 0, Informational 1, Low 3, Medium 5, High 8, Critical 10 |
The extension uses standard CEF dictionary keys, so ArcSight, QRadar and Sentinel's CEF parser map them without a custom parser:
| Extension key | Value |
|---|---|
rt | When the change was detected, epoch milliseconds |
externalId | The stable event id (OCSF metadata.uid) — de-duplicate on this |
cat / act | The OCSF class (Detection Finding, Entity Management, Scan Activity) and activity (Create, Update, Close, Delete, Completed) |
outcome | Finding status: New, In Progress, Suppressed or Resolved |
msg | The ignore reason, note preview or external-removal note, when there is one |
dhost / dst / dpt | The affected hostname, IP address and port |
suser / suid | Who made a DNS change, where DNS Watchdog knows |
start / end / cnt | Scan start, end and total changes, on the Scan Activity event |
cs1 tenantId, cs2 zone, cs3 issueType or entityType, cs4 scanId, cs5 changelogUrl, cs6 labels | Labelled custom strings |
cn1 ocsfClassUid, cn2 ocsfTypeUid | The OCSF class and type ids |
flexString1 scanType | daily_scan, manual_resync, zone_scan, record_rescan or initial_scan |
CEF is a flat, single-line format, so each line is a summary of the event: record snapshots, field-level diffs and the typed observable list are only carried by the JSON formats. Header fields escape \ and |; extension values escape \, = and line breaks, per the CEF specification. Names are clipped at 512 characters and extension values at 1,023.
The Splunk scheme is added to the credential automatically only for the Splunk HEC format. To send CEF to Splunk's raw endpoint, enter Splunk <token> as the credential.
Delivery and retries
Delivery is asynchronous and at-least-once:
- When a scan finishes with changes, DNS Watchdog maps the changes to OCSF events, splits them into batches of at most 100 events (about 200 KB), and queues one job per batch.
- A delivery worker posts each batch. A transient collector fault — an HTTP
429,5xx,408, a timeout or a dropped connection — is retried in-process three times with exponential back-off, honouringRetry-After. - If those attempts are exhausted the batch returns to the queue and is retried roughly every nine minutes, five times in all, before being dead-lettered for operator recovery. A collector outage of well under an hour therefore loses nothing.
- A permanent fault —
401/403(bad credential),400/404/413(wrong URL or format) — is not retried: no later attempt could succeed.
Because a batch can be redelivered, every event carries a stable metadata.uid (the DNS Watchdog changelog event id). De-duplicate on it if your pipeline is not already idempotent.
Channel status
The channel's status follows the same rules as every other channel — three consecutive failures mark it Error and pause delivery until a successful Test resets it — but for a SIEM channel a "failure" is a batch that was definitively rejected or gave up after all of its retries, not a single failed request. A collector blip never flags the channel.
The events
All events conform to OCSF 1.4.0 and share the standard envelope (the CEF format renders these same events as lines):
| Field | Value |
|---|---|
category_uid / category_name | The OCSF category of the class below |
class_uid / class_name | 2004 Detection Finding, 3004 Entity Management, or 6007 Scan Activity |
activity_id / activity_name | What happened — see each class |
type_uid / type_name | class_uid * 100 + activity_id and its name |
severity_id / severity | OCSF severity (0 Unknown … 5 Critical) |
time | When the change was detected, epoch milliseconds |
message | A one-line human summary |
metadata.version | 1.4.0 |
metadata.product | {"name": "DNS Watchdog", "vendor_name": "dnswatchdog.io", "version": …} |
metadata.uid | Stable per-event id (the changelog event id) — de-duplicate on this |
metadata.event_code | The DNS Watchdog change type, e.g. issue_detected, record_changed |
metadata.tenant_uid | Your organisation id |
metadata.log_name | dnswatchdog.scan |
metadata.labels | ["scan_type:daily_scan"] etc.; the test event carries ["test"] |
observables | Hostnames, IP addresses and ports extracted from the event, typed per OCSF |
unmapped | DNS Watchdog fields OCSF has no home for: scan_id, scan_type, zone_name, record_name, provider_id, changelog_url and the full issue/record snapshot |
Detection Finding (2004) — issues
One event per issue event. Severity is the issue's DNS Watchdog severity.
| DNS Watchdog change | activity_id | status_id |
|---|---|---|
| Issue detected | 1 Create | 1 New |
| Issue updated (re-graded severity or review-status change) | 2 Update | from the issue's review status |
| Issue ignored | 2 Update | 3 Suppressed (the reason is in comment) |
| Note added to an issue | 2 Update | from the issue's review status (the note preview is in comment) |
| Issue resolved | 3 Close | 4 Resolved |
finding_info carries the issue's uid, title, desc, types (the DNS Watchdog issue type, e.g. port_open_rdp), the analytic that raised it, and src_url pointing at your changelog. resources[0] names the affected DNS record (or zone) with its record type, value, IP address and port where relevant.
{
"category_uid": 2, "category_name": "Findings",
"class_uid": 2004, "class_name": "Detection Finding",
"activity_id": 1, "activity_name": "Create",
"type_uid": 200401, "type_name": "Detection Finding: Create",
"severity_id": 4, "severity": "High",
"status_id": 1, "status": "New",
"time": 1777342530000,
"message": "Port 3389 Open (RDP) detected on rdp.example.com",
"metadata": {
"version": "1.4.0",
"product": { "name": "DNS Watchdog", "vendor_name": "dnswatchdog.io", "version": "20260901.1" },
"uid": "c2f1…", "event_code": "issue_detected", "tenant_uid": "org_abc123",
"log_name": "dnswatchdog.scan", "logged_time": 1777342531000,
"labels": ["scan_type:daily_scan"]
},
"finding_info": {
"uid": "issue-…", "title": "Port 3389 Open (RDP)",
"desc": "Remote Desktop Protocol port 3389 is publicly accessible. …",
"types": ["port_open_rdp"],
"analytic": { "type_id": 1, "type": "Rule", "name": "port_open_rdp", "uid": "port_open_rdp" },
"created_time": 1777342200000, "modified_time": 1777342530000,
"src_url": "https://app.dnswatchdog.io/audit/changes?scan_id=…"
},
"resources": [
{ "type": "DNS Record", "name": "rdp.example.com", "uid": "rec-…",
"data": { "record_type": "A", "record_value": "203.0.113.5", "zone_name": "example.com", "ip_address": "203.0.113.5", "port": 3389 } }
],
"observables": [
{ "name": "resources[0].name", "type_id": 1, "type": "Hostname", "value": "rdp.example.com" },
{ "name": "unmapped.issue_data.ip_address", "type_id": 2, "type": "IP Address", "value": "203.0.113.5" },
{ "name": "unmapped.issue_data.port", "type_id": 11, "type": "Port", "value": "3389" }
],
"unmapped": { "scan_id": "…", "scan_type": "daily_scan", "issue_type": "port_open_rdp", "issue_severity": "high", "zone_name": "example.com", "record_name": "rdp.example.com", "changelog_url": "…" }
}Entity Management (3004) — DNS zone, record and provider changes
One event per change to a managed DNS entity. entity describes it (type is DNS Record, DNS Zone or DNS Provider) and carries its state; an update also carries the new state in entity_result, and unmapped.field_changes lists the exact fields that changed. Scanner metadata is excluded from these snapshots, as it is from every notification. Where DNS Watchdog knows who made the change, actor.user names them.
| DNS Watchdog change | activity_id | severity_id |
|---|---|---|
| Record discovered, zone discovered | 1 Create | 1 Informational |
| Record changed | 3 Update | 1 Informational |
| Record deleted, record removed externally, zone removed, provider removed | 4 Delete | 2 Low |
A record removed at the provider outside DNS Watchdog carries comment: "Record removed at the provider, outside DNS Watchdog".
Scan Activity (6007) — one per scan
A single activity_id: 2 (Completed) event closes every scan's batch, with scan.uid, scan.type_id (2 Scheduled for the daily scan, 1 Manual otherwise), start_time, end_time, duration, num_detections, and per-change-type counts under unmapped.counts_by_change_type. It doubles as a heartbeat: a detection rule that expects it daily will tell you if DNS Watchdog has gone quiet. It is only sent when Events to send is Findings, DNS changes and scan summaries.
Per-SIEM notes
Splunk
- In Splunk, enable the HTTP Event Collector and create a token (Settings → Data inputs → HTTP Event Collector → New Token). Set its default index and, optionally, a sourcetype.
- Collector URL:
https://<splunk-host>:8088/services/collector/event(Splunk Cloud:https://http-inputs-<stack>.splunkcloud.com/services/collector/event). - Format: Splunk HEC. Credential: the HEC token.
For CEF instead, use the raw endpoint — https://<splunk-host>:8088/services/collector/raw — with format CEF, enter Splunk <token> as the credential, and give the token a CEF sourcetype (the Splunk Add-on for CEF, or cef) so the extension keys are extracted.
Search with class_uid=2004 for findings, or metadata.event_code="issue_detected". The Splunk OCSF add-ons map these classes to CIM data models.
Microsoft Sentinel
Sentinel's Logs Ingestion API accepts a JSON array but authenticates with Entra ID tokens, which a static header cannot supply. Point the channel at a Logic App or Azure Function HTTP trigger that forwards to your Data Collection Rule, or ingest through Cribl Stream or Azure Event Hubs. Format: JSON array. If the trigger uses a shared-access URL, leave the credential empty; if it expects a key header, set the header name and credential.
If your workspace is fed by the Common Event Format (CEF) via AMA connector instead, choose format CEF and point the channel at a forwarder that accepts HTTPS and relays to the log forwarder's syslog port (Cribl Stream, Logstash, Fluent Bit) — that connector reads syslog, not HTTP. The lines arrive parsed into CommonSecurityLog with the extension keys mapped.
Google SecOps (Chronicle)
Create a Webhook feed (SIEM Settings → Feeds → Add new → Webhook, log type OCSF or a custom log type). Collector URL: the feed's endpoint URL. Format: JSON array (Chronicle splits JSON arrays into records). Auth header name: X-goog-api-key with the feed's API key as the credential; if the feed also requires a secret, put it in the URL as Chronicle instructs.
IBM QRadar and ArcSight
Both ingest CEF natively. In QRadar, add a log source with the HTTP Receiver protocol (HTTPS, POST, one event per line); use its listen URL as the collector URL, format CEF, and, if you enabled an authentication token on the receiver, set the header name and credential it expects. For ArcSight, point the channel at a SmartConnector or Logger receiver that accepts CEF over HTTPS, or at a forwarder that relays to your CEF syslog receiver.
Other collectors
Cribl Stream, Vector, Fluent Bit, Logstash, Elastic, Datadog and Sumo Logic all offer HTTP sources that accept a JSON array or NDJSON body with a token header, and most can parse CEF lines too. Choose the matching format, set the header name the source expects (Authorization: Bearer … is the default), and de-duplicate on metadata.uid (externalId in CEF).
Sending to more than one SIEM
You can add several SIEM channels, each with its own URL, format and scope — a findings-only feed for the SOC and a full feed into a data lake, say. Each is delivered, retried and tested independently.