Skip to contentSkip navigation

Connection Types

Every edge type in WhisperGraph — direction, source and target labels, and the physical-vs-virtual rules that decide how you traverse it.

Graph Schema
On this page (13)

Connection Types Documentation

Connections are what make a pre-joined graph worth querying. This page covers every edge type the engine exposes — each one's direction, the labels it runs between, and what it means. For the nodes on either end, see Entities; for the chains that string edges across layers, see Pivoting Examples.

The table below is generated from CALL db.relationshipTypes(), and that call is not perfectly stable. Measured 2026-08-09, six consecutive calls returned 50 edge types five times and 51 once: CONFLICTS_WITH is synthesized at expand time and appears in the listing only when the layer is warm. Its edges are real either way — anchor a prefix by name and it traverses. So the row set here is whatever the census last saw, and a type that comes and goes with a warm layer will come and go from this page too.

The From → To column is the source and target labels the call reports, not the ones a writer remembered. Where they name a label CALL db.labels() does not return, the row says so.

Direction matters. Several edges point the opposite way to how you would read them in English — NAMESERVER_FOR and MAIL_FOR run server → domain, so you traverse them backwards to answer "what serves this domain". The table's From → To column is the engine's own answer to which way each one points.

Edge types

DNS resolution & hierarchy

EdgeRowsFrom → ToWhat it means
RESOLVES_TO2,919,321,504HOSTNAMEIPV4, IPV6A host resolves to an IP (forward only — reverse-DNS via (ip)<-[:RESOLVES_TO]-(h)).
ALIAS_OF434,262,039HOSTNAMEHOSTNAMEA CNAME alias.
CHILD_OF2,338,085,185HOSTNAME, EMAILHOSTNAME, TLDA subdomain points up to its parent (and to the TLD).
NAMESERVER_FOR8,881,831,888HOSTNAMEHOSTNAMEA nameserver serves a domain (edge points server → domain).
MAIL_FOR562,591,148HOSTNAMEHOSTNAMEA mail server handles mail for a domain (edge points server → domain).
LINKS_TO10,851,011,448HOSTNAMEHOSTNAMEA web hyperlink between hosts — the largest edge type in the graph.

BGP & routing

EdgeRowsFrom → ToWhat it means
BELONGS_TO619,734,764IPV4, IPV6PREFIXAn IP falls inside an allocated prefix. It also carries the FEED_SOURCE → CATEGORY taxonomy hop, which this call does not declare.
ANNOUNCED_BY3,680,250,008IPV4, IPV6ANNOUNCED_PREFIXAn IP is covered by a BGP-announced prefix.
ROUTES1,423,425ASNPREFIX, ANNOUNCED_PREFIXAn ASN announces a prefix (matches in either direction).
HAS_NAME31,666ASNASN_NAMEAn ASN's registered network name (asn.name is the AS number; the network name lives on ASN_NAME).
BGP_NEIGHBOR483,674ASNASNThe canonical ASN↔ASN BGP adjacency edge.
PEERS_WITH483,674ASNASNAlias of BGP_NEIGHBOR. The same adjacency under its older name. Both spellings traverse.
BGP_PATH44,233,536BGP_PATH_OBSERVATIONASNOne hop of an observed AS path — the only route to the BGP_PATH_OBSERVATION label.
CONFLICTS_WITH15,558ANNOUNCED_PREFIXASNA multi-origin (MOAS) conflict over a prefix. Synthesized at expand time, so it appears in this listing only when the layer is warm.
ROA_AUTHORIZES_ORIGIN988,425ROAASNAn RPKI ROA authorizes an AS as origin.
ROA_AUTHORIZES_PREFIX687,030ROAPREFIXAn RPKI ROA authorizes a prefix.
OPERATES1,595TLD_OPERATORTLDA registry operates a TLD.

WHOIS & registration

EdgeRowsFrom → ToWhat it means
HAS_REGISTRAR649,320,946HOSTNAMEREGISTRARThe domain's current registrar.
PREV_REGISTRAR618,353,159HOSTNAMEREGISTRARA prior registrar.
HAS_EMAIL546,846,860HOSTNAMEEMAILA WHOIS contact email.
HAS_PHONE550,324,627HOSTNAMEPHONEA WHOIS contact phone.
REGISTERED_BY916,255,242HOSTNAME, ASN, PREFIXORGANIZATIONThe registrant or owning organization.
SAME_ORG_AS7,569ORGANIZATIONORGANIZATIONTwo organizations resolved to the same entity.

Geo

EdgeRowsFrom → ToWhat it means
LOCATED_IN118,196,249IPV4, IPV6CITYAn IP's GeoIP city (chain HAS_COUNTRY for the country).
HAS_COUNTRY194,925,670ANNOUNCED_PREFIX, ASN, CITY, HOSTNAME, IPV4, IPV6, ORGANIZATION, PHONE, PREFIX, REGISTERED_PREFIXCOUNTRYThe associated country.

Threat intelligence & attribution

EdgeRowsFrom → ToWhat it means
LISTED_IN10,931,701IPV4, IPV6, HOSTNAMEFEED_SOURCEAn indicator appears on a threat feed.
HAS_SIGNAL961IPV4, IPV6, HOSTNAME, ASN, PREFIXTHREAT_SIGNAL_TYPEA node carries a threat signal.
OPERATES_EXIT_NODE1,389IPV4TOR_RELAYAn IP operates a Tor exit relay.
DELEGATED_TO371,453PREFIX, IPV4, VENDORVENDORAddress space operated by a vendor (distinct from the WHOIS owner).
TAGGED_AS67,296IPV4, IPV6, HOSTNAME, ASN, CERTIFICATE† → THREAT_TAGA MISP-style classification tag on an indicator — the only route to the THREAT_TAG label.
USES_TECHNIQUE7,527ACTORATTACK_PATTERNA threat actor uses a MITRE ATT&CK technique.
USES_TACTIC872ATTACK_PATTERNATTACK_PATTERNA technique grouped under its ATT&CK tactic.
ATTRIBUTED_TO4THREAT_TAG, IPV4, IPV6, HOSTNAMEACTORAn indicator attributed to a named actor. Read the caveat below before using it.

Email security & TLS

EdgeRowsFrom → ToWhat it means
SPF_INCLUDE248,657,397HOSTNAMEHOSTNAMEAn SPF include: mechanism.
SPF_IP184,041,835HOSTNAMEIPV4, IPV6, PREFIXAn SPF ip4:/ip6: authorization.
SPF_A93,812,710HOSTNAMEHOSTNAMEThe SPF a mechanism.
SPF_MX84,451,018HOSTNAMEHOSTNAMEThe SPF mx mechanism.
SPF_EXISTS327,825HOSTNAMEHOSTNAMEThe SPF exists: mechanism.
SPF_REDIRECT2,751,803HOSTNAMEHOSTNAMEThe SPF redirect= modifier.
DMARC_REPORTS_TO53,736HOSTNAMEDMARC_RECIPIENTWhere a domain sends DMARC aggregate reports.
DKIM_SIGNED_BY30,782HOSTNAMEVENDORThe mail vendor whose DKIM key signs a domain's outbound mail.
EMITS_TLS_FINGERPRINT261IPV4TLS_FINGERPRINTAn IP presents a JA3/JARM TLS fingerprint.

Physical infrastructure

EdgeRowsFrom → ToWhat it means
AS_PRESENT_AT510,356ASNFACILITYA network is present in a datacenter.
IX_MEMBER56,831ASNINTERNET_EXCHANGEA network is a member of an IXP.
IX_HOSTED_AT4,503INTERNET_EXCHANGEFACILITYAn IXP is hosted in a facility.
CABLE_LANDS_AT3,184SUBMARINE_CABLECABLE_LANDINGA subsea cable lands at a landing point.
LANDING_NEAR5,241CABLE_LANDINGFACILITYA landing point is near a facility.
CDN_POP_AT1,677CDN_POPFACILITYA CDN PoP is in a facility.
FIBER_SEGMENT9,998FACILITYFACILITYA fiber link between facilities (symmetric).
PREFIX_IN_REGION3,288PREFIXCLOUD_REGIONA prefix sits in a cloud region.

Certificate Transparency

EdgeRowsFrom → ToWhat it means
SEEN_IN_CT29,453HOSTNAMECT_OBSERVATIONA host appears in a Certificate Transparency observation.

CERTIFICATE — declared as an endpoint by the call above, but CALL db.labels() returns no such label. A pattern anchored on it matches nothing, at HTTP 200, with no error to tell you why.

Declared but unpopulated

None. Every edge type in this census reported rows, and none came back declaredButEmpty. There are no schema stubs to route around today.

Rows generated from CALL db.relationshipTypes() YIELD type, count, sourceLabels, targetLabels, aliasOf, declaredButEmpty against https://graph.whisper.security, fetched 2026-08-09T21:11:53Z. The counts render from that same census, so a replica disagreeing by a few million moves the number without moving the table.

Where the planes are thin

Some of these planes are small enough that a zero-row result says more about Whisper's coverage than about the indicator, and reading one as evidence of absence is the most expensive mistake on this page. The row count in the table above is what tells them apart.

The ATT&CK layer is a curated reference plane, not Whisper's own attribution: 7,527 USES_TECHNIQUE and 872 USES_TACTIC edges reflect what public reporting has mapped. ATTRIBUTED_TO — the edge that would join an actor to live infrastructure — holds 4 edges on production. It answers no attribution question at scale, and an empty result from it is no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at., never evidence of absence.

The three email and TLS planes are not the same size, and lumping them together hides which results you can trust: DKIM_SIGNED_BY holds 30,782 edges and DMARC_REPORTS_TO 53,736 — populated planes where an empty result usually means the domain publishes no such record. EMITS_TLS_FINGERPRINT holds 261, roughly a hundredth of either.

Coverage on this plane is partial. Expect no match on almost any indicator. A zero-row result here means Whisper holds no observation — not that the host shares no infrastructure.

Coverage on this plane is partial. github.com has none. paypal.com has none. A zero-row result here means Whisper holds no CT observation for that host. It never means the host has a clean certificate history. If certificate history is load-bearing for your decision, query a CT log directly — crt.sh or the Google CT API — and come back with the hostnames you find.

Physical vs. virtual edges

Edge types come in two kinds, and the distinction changes how you write the query. Read the split from the engine rather than from a list here: CALL db.schema('json') marks every edge type virtual: true or false. Measured 2026-08-09, that call reported 20 physical and 30 virtual.

Physical edges are materialized on disk — the DNS, geo and SPF sets, and most of the WHOIS set. An unanchored MATCH ()-[r:RESOLVES_TO]->(h) returns rows.

Virtual edges are synthesized by the VDP layer at expand time and are not in the physical store: the routing set, the whole threat and attribution set, the DMARC/DKIM/TLS-fingerprint edges, SEEN_IN_CT, and the physical-infrastructure set. BELONGS_TO is mixed — the IP → PREFIX side is stored, the FEED_SOURCE → CATEGORY taxonomy hop is synthesized — and the engine treats it as virtual when it plans a traversal. Two rules follow:

  • Label or anchor at least one endpoint. A pattern with both ends bare is refused, not answered: MATCH (a)-[:LISTED_IN]->(b) RETURN a.name, b.name returns HTTP 400 query-unservable, naming the edge type and explaining that an unanchored scan of a synthesized layer would return zero rows. Label one end — MATCH ()-[:LISTED_IN]->(f:FEED_SOURCE) — and it answers.
  • Write them as explicit single hops. Variable-length expansion over a synthesized edge is expensive, not broken: it will not finish on a wide plane. Stage the hops with WITH instead.

ROUTES and HAS_NAME do appear in db.relationshipTypes() with real counts — read them off the table above. Anchor them and they work.

Danger — count(r) lies on three edge types. MATCH ()-[r:LISTED_IN]->() RETURN count(r) returns 0 at HTTP 200 in milliseconds, while db.relationshipTypes() reports 10,931,701 LISTED_IN edges. ANNOUNCED_BY and CONFLICTS_WITH do the same. Read the count from CALL db.relationshipTypes() YIELD type, count or GET /api/query/stats — never from count(r).

CALL db.schema() in its default form attaches a traversalHints list to 31 of the 51 relationship rows — copy-pasteable starter patterns, and not one per virtual type as this page used to say. Check a hint before you trust it. One of them anchors on CERTIFICATE, a label CALL db.labels() does not return, so running it verbatim gives you zero rows at HTTP 200 and no error at all (measured 2026-08-09). The db.schema('json') form carries no hints. See Best Practices for the full set of query rules.

Confirm an edge before you traverse

cypher · runnablegraph.whisper.securitySign in to run
CALL db.relationshipTypes() YIELD type, sourceLabels, targetLabels
RETURN type, sourceLabels, targetLabels ORDER BY type

db.relationshipTypes() lists every edge type with the source and target labels observed on it, and it is cheap — it answers immediately. Checking it first — alongside db.labels() — is the fastest cure for silent empty results from a mistyped edge name.