Skip to content
Integrations
Skip navigation

What Every Connector Guarantees

The field contract the four table-writing connectors share: guaranteed/conditional columns, what's absent on failure, and verdict semantics.

Published Last updated

On this page (6)

What Every Connector Guarantees Documentation

Splunk writes whisper_threat_level onto your events, Microsoft Sentinel writes threatLevel into WhisperThreatIntel_CL, OpenCTI writes a note on the observable, the Wazuh connector writes data.whisper.level into a new alert beside the original. Four spellings, one fact: all four table-writing connectors ask the same graph of 7.5B nodes and 39.7B edges, 134 intelligence feeds. This is the contract those spellings share, and what a detection has to do when one of them does not arrive.

The Whisper module for MISP writes MISP objects and attributes rather than a queryable table, so its output shape is on MISP integration — overview instead.

Guaranteed, conditional, absent

Guaranteed means the field is on every record that connector writes. Conditional means it arrives only when the graph held that fact. Absent means the connector does not carry it at all — a contract rather than an omission, so a rule that needs the fact needs a different connector, or a query of your own.

Only the indicator and its type are guaranteed everywhere — and guaranteed means written, not correct. Everything the graph supplies — score, level, per-feed evidence, threat flags, network context — is conditional, and some is absent on some connectors. Which field carries which fact, and what its absence means there, belongs to the connector's own reference page: Splunk, Sentinel, OpenCTI and Wazuh.

Missing is not zero. A null score is an absence of evidence; a zero is evidence. A rule that coalesces them has stopped measuring.

Absence has four shapes, and only one is null

The same missing fact arrives differently in each tool, so the test that finds it differs too. Splunk leaves the field off the event, so isnotnull() is the test. Sentinel writes the string columns of WhisperInfraContext_CL as an empty string, never null — isnotempty() is correct there and isnotnull() passes every row. OpenCTI creates no note at all. Wazuh strips nullable fields before sending. A rule ported between two of these without changing its emptiness test has stopped filtering.

One threat level, and it has six values

NONE · INFO · LOW · MEDIUM · HIGH · CRITICAL

This is the enum explain() returns and every connector carries through. Where a connector page names a shorter ladder, this page governs.

INFO is the value that gets dropped. It is what a clean, well-known address comes back as, so a rule whose lowest band is LOW discards exactly the observables its author assumed were covered — and those rows look identical to rows that were never enriched.

Read coverage before the level

A level is not a verdict. The block below, transcluded from the one place it is written, governs every field a connector writes.

Every Whisper verdict answers two independent questions. band tells you how bad. coverage tells you what we actually looked at. Read both. They are a grid, not a ladder.

Only known-clean — coverage: known-clean. In coverage, no malicious evidence. licenses the word "clean". Every other value is not-clean — and no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at. and deadline-hit mean unknown, which is a different thing again.

whisper.assess, whisper.assessUrl, whisper.explain and whisper.walk all return coverage, and it is not about the same thing in each.

coverageWhat it meansWhat to do
known-clean — coverage: known-clean. In coverage, no malicious evidence.We hold data at this granularity and nothing malicious is in it.Treat as clean. This is the only value that licenses closing a ticket on "clean."
malicious-evidenced — coverage: malicious-evidenced. In coverage, with positive evidence of malice.Some positive evidence of malice exists. It may be a single feed at weight 0.5. It does not mean the band is high.Read evidence[] for feed-source-count, then run explain() for the per-feed provenance, weights and timestamps. A count of 1 on a low-weight aggregate list is a lead, not a finding.
ambiguous — coverage: ambiguous. In coverage, and the evidence points both ways.The evidence points both ways — for example an anonymising-egress signal alongside generic abuse listings.Escalate to a human. Do not automate a decision on this value.
no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at.We have never observed this host.Unknown. Never benign. Ask a different question — the container, the operator, the age — and escalate with "we have no observation of this host", never with "it came back clean."

Every one of these arrives as a populated row. no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at. is a row that says no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at.; it is never an empty result set. If a query returns zero rows, the first hypothesis is that the query is wrong, not that the host is clean.

Which procedure carries coverage:

ProcedureReturns coverage?What its coverage is about
whisper.assessYesThreat coverage. The four values above.
whisper.assessUrlYesA path axis, not a host axis — read the contract before gating on it.
whisper.walkYes, but not a verdictAtlas and vendor adjacency — whether the host is reachable in the graph's structure. Emits presence-axis values only.
whisper.explainYesThreat coverage; for a host or an address, the same value whisper.assess returns. A NONE level from explain() is a score, not a clean verdict: read coverage beside it.

structural-onlywalk — a whisper.walk value describing atlas adjacency. Not an assess coverage value. Do not gate on it. is a whisper.walk value describing atlas adjacency. It is not a whisper.assess value, and a branch keyed on it in an assess result is unreachable — see the full contract.

A table that stops filling has to be audible

The failure that costs the most is not a wrong row — it is no row, and a pipeline that quietly stops writing looks exactly like a quiet week. Watch the tables by name, on a schedule: keep the names you expect on the right-hand side of an outer join, and a store nothing has ever written surfaces as a zero instead of dropping out of the result. Treating a missing table as "nothing to report" is the same mistake as treating no data as a clean verdict, one layer down.

The Microsoft Sentinel form is on Data Reference; the same join works against whatever store the other three write into.

When a field disagrees with this page

A field that contradicts this page goes to Support, which lists what to send.