DNS & Email Security

Trace SPF chains, DNSSEC validation, MX records, CNAME hops, and detect dangling DNS records.

Updated May 2026recipes Integration

DNS & Email Security Documentation

You're auditing DNS configurations, validating SPF coverage, and checking DNSSEC deployment.

Quick Triage

Nameserver Inventory

Get all nameservers currently delegated for a domain.

-- Authoritative nameservers for a domain
MATCH (ns:HOSTNAME)-[:NAMESERVER_FOR]->(h:HOSTNAME {name: "microsoft.com"})
RETURN ns.name LIMIT 10

Sample output:

[
  {"ns.name": "ns1-39.azure-dns.com"},
  {"ns.name": "ns2-39.azure-dns.net"},
  {"ns.name": "ns3-39.azure-dns.org"},
  {"ns.name": "ns4-39.azure-dns.info"}
]

Tip: Multiple NS records across different TLDs (.com, .net, .org) is standard practice for fault tolerance. If all NS records are under the same TLD, that's a single point of failure.

Mail Server Inventory

List all mail servers that handle inbound email for a domain.

-- MX records for a domain
MATCH (mx:HOSTNAME)-[:MAIL_FOR]->(h:HOSTNAME {name: "google.com"})
RETURN mx.name

Sample output:

[{"mx.name": "smtp.google.com"}]

Tip: The graph stores MX records as MAIL_FOR edges from the mail server hostname to the domain it serves. Cross-check the mail server's own IP and ASN to verify it's on expected infrastructure.

Deep Dive Investigation

SPF Include Chain Audit

Trace the full tree of SPF includes to understand the complete authorized sender set.

-- Recursive SPF include chain (up to 3 hops)
MATCH (h:HOSTNAME {name: "microsoft.com"})-[:SPF_INCLUDE*1..3]->(inc:HOSTNAME)
RETURN DISTINCT inc.name ORDER BY inc.name LIMIT 20

Sample output:

[
  {"inc.name": "_spf-a.microsoft.com"},
  {"inc.name": "_spf-b.microsoft.com"},
  {"inc.name": "_spf-c.microsoft.com"},
  {"inc.name": "_spf-d.microsoft.com"},
  {"inc.name": "_spf-ssg-a.microsoft.com"}
]

Tip: The SPF spec caps includes at 10 DNS lookups. Deep include chains close to that limit risk "permerror" for legitimate email. Count the distinct nodes returned to check depth.

SPF IP Authorization

See the exact IP ranges authorized to send mail on behalf of a domain.

-- IP ranges authorized in SPF (direct + one level of includes)
MATCH (h:HOSTNAME {name: "google.com"})-[:SPF_INCLUDE]->(spf:HOSTNAME)
OPTIONAL MATCH (spf)-[:SPF_IP]->(range)
RETURN spf.name, collect(range.name) AS authorized_ranges

Sample output:

[{
  "spf.name": "_spf.google.com",
  "authorized_ranges": ["74.125.0.0/16", "209.85.128.0/17", "2001:4860:4000::/36", "2404:6800:4000::/36"]
}]

Tip: Broad IP ranges (like /16 or /17) in SPF records mean any server in that range can send as your domain. For a security audit, verify each range actually belongs to the email provider you're using.

Full SPF Mechanism Audit

Get a complete breakdown of all SPF mechanisms for a domain.

-- All SPF mechanisms (include, ip, a, mx, redirect, exists)
MATCH (h:HOSTNAME {name: "microsoft.com"})
      -[r:SPF_INCLUDE|SPF_IP|SPF_A|SPF_MX|SPF_REDIRECT|SPF_EXISTS]->(target)
RETURN type(r) AS mechanism, target.name AS authorized LIMIT 20

Sample output:

[
  {"mechanism": "SPF_INCLUDE", "authorized": "_spf-a.microsoft.com"},
  {"mechanism": "SPF_INCLUDE", "authorized": "_spf-b.microsoft.com"},
  {"mechanism": "SPF_INCLUDE", "authorized": "_spf-c.microsoft.com"},
  {"mechanism": "SPF_INCLUDE", "authorized": "_spf-d.microsoft.com"},
  {"mechanism": "SPF_INCLUDE", "authorized": "_spf-ssg-a.microsoft.com"}
]

Tip: Check for SPF_REDIRECT — a redirect mechanism replaces the entire SPF policy with another domain's policy. If that target domain has a permissive policy, your effective policy is permissive too.

Domain Hierarchy

Understand the parent-child structure of a domain namespace.

-- Walk the domain hierarchy from a subdomain to its roots
MATCH (h:HOSTNAME {name: "mail.google.com"})-[:CHILD_OF*1..3]->(parent)
RETURN h.name AS subdomain, parent.name AS ancestor LIMIT 10

Sample output:

[
  {"subdomain": "mail.google.com", "ancestor": "google.com"},
  {"subdomain": "mail.google.com", "ancestor": "com"}
]

Tip: Use this to confirm zone delegation — a subdomain should share the same effective zone as its parent unless it has its own NS records.

Batch Nameserver Audit

Check the nameservers for multiple domains at once.

-- Nameservers for a set of domains
UNWIND ["google.com", "cloudflare.com", "microsoft.com"] AS domain
MATCH (h:HOSTNAME {name: domain})
OPTIONAL MATCH (ns:HOSTNAME)-[:NAMESERVER_FOR]->(h)
RETURN domain, collect(ns.name) AS nameservers

Sample output:

[
  {"domain": "google.com", "nameservers": ["ns1.google.com", "ns2.google.com", "ns3.google.com", "ns4.google.com"]},
  {"domain": "cloudflare.com", "nameservers": ["bella.ns.cloudflare.com", "chelsea.ns.cloudflare.com", "graham.ns.cloudflare.com"]},
  {"domain": "microsoft.com", "nameservers": ["ns1-39.azure-dns.com", "ns2-39.azure-dns.net", "ns3-39.azure-dns.org", "ns4-39.azure-dns.info"]}
]

Tip: Comparing nameservers across an organization's portfolio is a fast way to find outliers — a domain that's still on an old DNS provider after a migration, or a test domain left on a default registrar nameserver.

Who Operates a TLD?

You need to identify the registry operator responsible for a top-level domain — useful when escalating abuse complaints or understanding jurisdiction.

-- Registry operator for a TLD
MATCH (op:TLD_OPERATOR {name: "VeriSign Global Registry Services"})-[:OPERATES]->(tld:TLD)
RETURN op.name AS operator, collect(tld.name) AS tlds

Sample output:

[{"operator": "VeriSign Global Registry Services", "tlds": ["com", "net"]}]

Tip: Most TLD operators run only one or a few TLDs. For abuse escalation, the OPERATES relationship gives you the authoritative registry responsible for the zone.

Check Email Security Posture

Quickly assess whether a domain has SPF configured and DNSSEC enabled.

-- Email security posture: SPF and DNSSEC
MATCH (h:HOSTNAME {name: "stripe.com"})
OPTIONAL MATCH (h)-[:SPF_INCLUDE]->(spf)
OPTIONAL MATCH (h)-[:SIGNED_WITH]->(algo:DNSSEC_ALGORITHM)
RETURN h.name,
       count(DISTINCT spf) AS spf_includes,
       collect(DISTINCT algo.name) AS dnssec_algorithms

Sample output:

[{"h.name": "stripe.com", "spf_includes": 3, "dnssec_algorithms": []}]

Tip: An empty dnssec_algorithms list means DNSSEC signing data was not available for this domain. spf_includes greater than zero confirms an SPF policy exists. For full SPF coverage detail, use the SPF include chain recipe above.



Splunk equivalents

For SPF/DMARC posture audits and dangling DNS detection in SPL, see Splunk Use Cases. The whisper_spf_chain and whisper_cname_chain macros wrap the same Cypher patterns — see Investigation Macros.