whisper.identify() — Identity & Assessment
Answer whose infrastructure a host is, whether it is dangerous, and — when there's no direct match — what sits around it. The identity family: identify, assess, walk.
On this page (4)
whisper.identify() — Identity & Assessment Documentation
Three procedures answer the questions you ask about a host before you decide what to do with it: whose infrastructure is this, is it dangerous, and — when neither has a clean answer — what sits around it. They are built to run over a batch of hosts and return decision-ready columns, so they slot straight into triage and enrichment pipelines.
whisper.identify(hosts) — whose infrastructure is this
whisper.identify() resolves a host to the vendor or service that operates it. Pass one host or a batch (1 to 256 per call — larger batches are rejected, not truncated) and it returns the canonical identity plus the evidence behind it.
CALL whisper.identify(["api.stripe.com", "cdn.shopify.com"])
YIELD host, vendor_id, canonical_name, category, roles, host_class, band
RETURN host, vendor_id, canonical_name, category, host_class, band
| Column | Meaning |
|---|---|
host | The input host. |
vendor_id | Stable identifier of the resolved vendor (github, stripe, …). |
canonical_name | The resolved vendor or service identity. |
category | What kind of service it is (saas, cloud, cdn, …). |
roles | The roles the host plays (DNS_OPERATOR, MAIL_RECEIVER, …). |
host_class | A coarse classification of the host — multi_tenant_user_content flags platforms where anyone can publish. |
band | Attribution band. A host with no match comes back as UNKNOWN with confidence 0.0 — it never fails the batch. |
confidence | How strongly the evidence supports the identity. |
evidence | The signals that produced the match. |
Use it to label infrastructure at scale — attributing a list of hostnames from a log or an alert to the services behind them, without a hop-by-hop traversal per host.
whisper.assess(hosts) — is it dangerous
whisper.assess() answers the safety question, and — critically — tells you what it actually looked at. It accepts a single host as a bare string or a batch as a list; both return the same seven columns: CALL whisper.assess("github.com") returns band: INFO, coverage: known-clean.
CALL whisper.assess(["example.com", "185.220.101.1"])
YIELD host, label, band, coverage, signals, evidence
RETURN host, label, band, coverage
| Column | Meaning |
|---|---|
label | The assessment (clean, suspicious, …). |
band | Severity band (NONE … CRITICAL). |
sub_labels | Finer-grained labels behind the top-level label. |
coverage | What we looked at, on the malice question — four values on production. This is the column to gate on, and it is not a strength scale. See Coverage. |
signals | The threat signals that fired. |
evidence | The underlying evidence. |
Every Whisper verdict answers two independent questions.
bandtells you how bad.coveragetells 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 and whisper.assessUrl return coverage. whisper.explain does not.
coverage | What it means | What 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 —:
| Procedure | Returns coverage? | What its coverage is about |
|---|---|---|
whisper.assess | Yes | Threat coverage. The four values above. |
whisper.assessUrl | Yes | A path axis, not a host axis — read the contract before gating on it. |
whisper.walk | Yes, but not a verdict | Atlas and vendor adjacency — whether the host is reachable in the graph's structure. Emits presence-axis values only. |
whisper.explain | No | Returns score, level, explanation, factors and sources. There is no coverage column, so a NONE level from explain() is not a clean verdict. |
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.
whisper.walk(host [, depth] [, budget_ms]) — the structural neighborhood
When whisper.identify() has no direct match, whisper.walk() returns a bounded structural neighborhood — the host's siblings and the nearest known vendors — so you still get context to reason about an unknown host. It is depth- and budget-bounded so it stays fast on large networks.
CALL whisper.walk("unknown-host.example", 2, 800)
YIELD host, no_atlas_match, nearest_known_vendors, siblings, coverage
RETURN host, no_atlas_match, nearest_known_vendors, coverage
| Column | Meaning |
|---|---|
no_atlas_match | true when the host resolved to no direct vendor identity. |
nearest_known_vendors | The closest identified vendors in the surrounding infrastructure. |
siblings | Hosts that share infrastructure with the input. |
coverage | How much of the neighborhood the walk reached — atlas and vendor adjacency. A presence value, not a verdict, and it uses a different vocabulary from assess. Read arms before you read it. |
arms | Per-arm traversal detail, including deadline_hit when a budget expired. |
The optional second argument is the traversal depth (1 to 6, default 2) and the third is a per-arm budget in milliseconds (default 3000). When the budget runs out, the row comes back with partial data and arms.deadline_hit: true — a partial walk is a result, not an error. Keep both modest — this is a fallback for the case where a direct identity lookup came back empty, not a general graph crawler.
The same word, two meanings — and on one indicator they flatly disagree.
CALL whisper.assess(["185.220.101.1"])→coverage: "ambiguous"— there is evidence, pointing both ways.CALL whisper.walk("185.220.101.1")→coverage: "no-data"— no atlas match, andarms_completed: 7with nothing truncated.Both rows are correct. They answer different questions:
assessreports threat coverage,walkreports structural adjacency. Never gate a verdict on awalkrow. A branch written againstwalk's vocabulary in anassessresult is unreachable, and the branch it leaves you missing is malicious-evidenced — coverage: malicious-evidenced. In coverage, with positive evidence of malice..
Where these fit
- Start with
identifyto attribute known infrastructure. - Use
assessfor the safety verdict on a batch, and always readcoveragebefore you act onlabel. - Fall back to
walkonly whenidentifyreturns no match and you need surrounding context.
For a single scored threat verdict with per-feed evidence, use explain(). To band a full URL rather than a host, use whisper.assessUrl() — and read its page first, because its coverage column behaves differently from the one above. For the full procedure catalog, see the Procedures overview.