Security

Vendor Domain Security Audit: WHOIS, DNS, SSL and Email Security Checklist

Automate public domain checks before approving a SaaS vendor, service provider, affiliate partner, or technical integration.

May 18, 202612 min readVendor Risk · WHOIS · DNS · SSL · Email Security

A vendor's domain is part of your supply chain. If a SaaS vendor connects to your SSO, sends email on your behalf, loads JavaScript on your frontend, or receives customer data, its public domain posture becomes a business risk you inherit.

The failure modes are not exotic. A vendor domain can expire. A registrar or nameserver can change without notice. An SSL certificate can expire or be reissued for the wrong host. A critical email domain may have no DMARC record. Old subdomains can keep pointing at abandoned third-party services. The initial vendor onboarding review is often done once, saved as a PDF, and never rechecked.

A vendor domain security audit turns those public signals into a repeatable technical workflow. It does not replace legal review, SOC 2 review, penetration testing, or contractual controls. It gives developers, CTOs, CISOs, security engineers, procurement teams, and compliance teams a practical way to evaluate domain-level risk before and after vendor approval. For broader external exposure programs, this audit can feed an attack surface monitoring workflow.

What Is a Vendor Domain Security Audit?

A vendor domain security audit is an automated review of public domain signals associated with a third party: registration data, RDAP and WHOIS fields, DNS records, email authentication records, SSL certificate health, exposed subdomains, and ongoing change events.

It is not a full penetration test. It does not authenticate into the vendor's systems, scan private infrastructure, or prove that the vendor is secure. Instead, it answers a narrower question: does this vendor's public domain footprint look stable, maintained, and consistent with the access or trust we are about to grant?

That narrower question matters because domain signals are public, cheap to query, and easy to monitor. They also degrade over time. A clean domain at onboarding can become risky six months later if nameservers move, MX records change, DMARC is removed, or a staging subdomain appears.

Why Vendor Domain Risk Matters

Vendor domain risk is not limited to obvious security suppliers. Any third party that touches identity, email, customer data, analytics, payments, or frontend code deserves domain due diligence.

  • SaaS connected to SSO: a compromised or abandoned vendor domain can affect authentication redirects, login pages, OAuth callbacks, and trust decisions made by employees.
  • Email provider: weak SPF, DKIM, or DMARC alignment can expose outbound communications to spoofing, delivery problems, or abuse.
  • Analytics tool loaded on the frontend: a third-party script host becomes part of the customer browser execution path.
  • Affiliate partner: unexpected redirects, weak domain ownership, or lookalike domains can create fraud and attribution risk.
  • Service provider with customer data access: domain instability can become a compliance concern when the vendor handles personal data, support tickets, or exports.
  • Acquisition or technical partnership: domain age, registrar consistency, DNS ownership, and subdomain hygiene can surface integration risks before a deal or rollout.

The goal is not to reject every vendor with one warning sign. The goal is to document risk, route exceptions to the right owner, and avoid approving a critical integration based only on a security questionnaire.

Step 1 — Check WHOIS and RDAP Data

Start with the domain registration layer. WHOIS and RDAP data describe the administrative state of the domain: when it was created, when it expires, which registrar controls it, which nameservers are authoritative, and which EPP status codes are active.

Check at minimum:

  • Domain age and creation date.
  • Expiration date and days until expiry.
  • Registrar name.
  • Authoritative nameservers.
  • EPP status codes such as transfer locks, holds, redemption, or pending delete states.
  • Registrant organization or contact visibility when available.
  • Newly registered or young domain signals when the data source provides them.

Red flags include a domain created very recently for a vendor that claims a long operating history, an expiration date inside your approval or renewal window, registrar or nameserver changes that were not disclosed, unexpected EPP status codes, and WHOIS data that does not match the vendor's claimed maturity.

Treat young domains carefully. A young domain is not automatically malicious. It may belong to a new product, subsidiary, rebrand, or acquisition. But if the vendor wants SSO access or customer data access from a domain registered last week, that fact should be visible in the risk record.

Step 2 — Audit DNS Records

DNS tells you how the vendor's domain is used. For vendor due diligence, query both infrastructure records and email security records with a DNS lookup API.

Core records:

  • A and AAAA for web and API hosts.
  • CNAME for third-party service dependencies.
  • MX for inbound mail handling.
  • TXT for verification and security policies.
  • SPF through TXT records beginning with v=spf1.
  • DKIM selector records used to sign outbound email.
  • DMARC at _dmarc.example.com.
  • CAA to restrict which certificate authorities can issue certificates.
  • MTA-STS policy discovery records.
  • TLS-RPT reporting records for mail transport security failures.

The red flags depend on vendor role. A vendor that sends customer email should not have missing email authentication. A vendor that hosts critical application code should not have unexplained CNAMEs pointing at abandoned services.

  • No DMARC record on a domain used for email.
  • DMARC policy left at p=none for a critical sender domain with no documented path to enforcement.
  • SPF records that are too permissive, such as broad IP ranges or excessive includes.
  • Unexpected MX providers that do not match the vendor's declared email platform.
  • No CAA record on high-value domains.
  • CNAME records pointing to third-party services that appear unused, expired, or unclaimed.
  • DNS records that contradict the vendor's stated architecture or data flow.

DNS should be compared against the vendor's intended use. A domain used only for documentation has a different risk profile than a domain used for SSO, transactional email, API callbacks, or production JavaScript.

Step 3 — Check SSL Certificate Health

SSL certificate checks confirm whether the vendor's HTTPS endpoints are currently trusted, which certificate authority issued the certificate, which hostnames are covered, and when renewal is required.

Check:

  • Certificate expiration and days remaining.
  • Issuer organization.
  • Subject Alternative Names (SANs).
  • Hostname mismatch.
  • Weak, broken, or unexpected certificate chain.
  • Newly issued certificates on suspiciously new domains.

SSL alone is not a security signal. A valid certificate proves that a certificate was issued for a hostname; it does not prove that the vendor is legitimate, mature, or safe. Attackers can obtain valid certificates for newly registered domains. Expired or mismatched certificates are useful risk signals, but valid certificates should be correlated with WHOIS, DNS, email security, and subdomain context.

Step 4 — Discover Exposed Subdomains

Subdomains often reveal the operational reality behind a vendor's polished homepage. Development, staging, support, dashboard, and authentication endpoints can expose risk that never appears in a questionnaire.

Review discovered subdomains that include patterns such as:

  • admin
  • staging
  • dev
  • test
  • old
  • beta
  • internal
  • dashboard
  • auth
  • api

The main risks are exposed admin panels, public staging environments, forgotten SaaS integrations, dangling CNAME records, undocumented API endpoints, and legacy systems still reachable from the internet. A vendor does not need to have a perfect subdomain inventory, but high-risk names should be reviewed before the vendor receives privileged access or handles sensitive data. A subdomain discovery API makes this check repeatable across every vendor domain.

Step 5 — Build a Simple Vendor Domain Risk Score

A risk score keeps the audit consistent. It should be simple enough to explain during procurement review and flexible enough to change by vendor criticality.

Example scoring model:

  • Domain expires in less than 30 days: +25.
  • Domain created less than 90 days ago: +25.
  • No DMARC record: +20.
  • DMARC policy is p=none: +10.
  • SSL expires in less than 14 days: +20.
  • Nameservers recently changed: +20.
  • Suspicious or exposed subdomain found: +30.
  • SPF allows too broad a sender range: +15.
  • Unexpected MX provider: +15.
SignalRiskSuggested Action
Domain expires in less than 30 daysHighAsk the vendor to renew before approval or document an exception with an owner.
Domain created less than 90 days agoMedium to highConfirm product launch, rebrand, acquisition, or alternate corporate domain.
No DMARC recordHigh for email sendersRequire an email security remediation plan before allowing production sending.
DMARC is p=noneMediumAsk whether monitoring is temporary and when enforcement is planned.
SSL expires in less than 14 daysHighRequire renewal or proof of automated certificate management.
Nameservers recently changedMedium to highValidate the change against onboarding documentation and vendor contacts.
Suspicious or exposed subdomain foundHighReview the host, ownership, access controls, and whether it is in scope for your integration.
SPF allows too broad a sender rangeMediumAsk the vendor to narrow SPF includes and IP ranges.
Unexpected MX providerMediumConfirm the provider is approved and matches the vendor's declared mail flow.

Use the score to guide action, not as a blind allow-or-block mechanism. A low-risk analytics vendor may pass with warnings. A vendor integrated with SSO, billing, or customer data should face a higher bar.

Step 6 — Automate the Audit with APIs

The audit becomes useful when it is repeatable. A vendor onboarding workflow can call several APIs, normalize the result, apply a scoring model, and store the report with the vendor record.

Combine:

Example normalized audit output:

vendor-audit.jsonJSON
{
  "domain": "vendor-example.com",
  "checked_at": "2026-05-18T09:30:00Z",
  "risk_score": 65,
  "risk_level": "high",
  "signals": {
    "domain_age_days": 42,
    "expires_in_days": 21,
    "registrar": "Example Registrar LLC",
    "nameservers_changed_recently": false,
    "dmarc": {
      "present": true,
      "policy": "none"
    },
    "spf": {
      "present": true,
      "broad_sender_range": true
    },
    "ssl": {
      "valid": true,
      "expires_in_days": 9,
      "issuer": "Example CA",
      "hostname_match": true
    },
    "subdomains": {
      "reviewed": 28,
      "suspicious": ["staging.vendor-example.com"]
    }
  },
  "recommended_action": "Review before approval and request remediation for SSL renewal, SPF scope, and staging exposure."
}

Example: Vendor Domain Audit in Python

The following example follows the public WhoisJSON OpenAPI contract: base URL https://whoisjson.com/api/v1, Authorization: TOKEN=... authentication, /whois for registration data, /nslookup for DNS records, /ssl-cert-check for certificate data, and /subdomains for subdomain discovery. Check the API documentation before deploying and keep the scoring thresholds aligned with your vendor policy.

vendor_domain_audit.pyPython
import json
import os
from datetime import datetime, timezone

import requests


API_KEY = os.environ["WHOISJSON_API_KEY"]
BASE_URL = "https://whoisjson.com/api/v1"
SUBDOMAIN_REVIEW_TERMS = (
    "admin", "staging", "dev", "test", "old",
    "beta", "internal", "dashboard", "auth", "api"
)

dns_cache = {}


def api_get(path, params):
    headers = {"Authorization": f"TOKEN={API_KEY}"}
    url = f"{BASE_URL}{path}"
    try:
        response = requests.get(url, headers=headers, params=params, timeout=15)
        response.raise_for_status()
        return {"ok": True, "data": response.json()}
    except requests.exceptions.HTTPError as exc:
        return {
            "ok": False,
            "error": "http_error",
            "status": exc.response.status_code if exc.response else None,
            "message": str(exc),
        }
    except requests.exceptions.RequestException as exc:
        return {"ok": False, "error": "request_error", "message": str(exc)}


def get_whois(domain):
    return api_get("/whois", {"domain": domain})


def get_dns(domain, record_type):
    # /nslookup returns all supported records in one response:
    # A, AAAA, CNAME, MX, NS, TXT, SOA, CAA, DMARC, BIMI, MTASTS, TLSRPT.
    if domain not in dns_cache:
        dns_cache[domain] = api_get("/nslookup", {"domain": domain})

    result = dns_cache[domain]
    if not result["ok"]:
        return result

    return {
        "ok": True,
        "data": result["data"].get(record_type, []),
    }


def get_ssl(domain):
    return api_get("/ssl-cert-check", {"domain": domain})


def get_subdomains(domain):
    return api_get("/subdomains", {"domain": domain})


def days_until(date_string):
    if not date_string:
        return None
    formats = [
        "%Y-%m-%d %H:%M:%S",
        "%Y-%m-%dT%H:%M:%S.%fZ",
        "%Y-%m-%dT%H:%M:%SZ",
    ]
    for fmt in formats:
        try:
            value = datetime.strptime(date_string, fmt).replace(tzinfo=timezone.utc)
            return (value - datetime.now(timezone.utc)).days
        except ValueError:
            pass
    try:
        value = datetime.fromisoformat(date_string.replace("Z", "+00:00"))
        return (value - datetime.now(timezone.utc)).days
    except ValueError:
        return None


def first_txt(records):
    if not records:
        return None
    if isinstance(records, list):
        return " ".join(str(item) for item in records)
    return str(records)


def find_suspicious_subdomains(subdomain_result):
    if not subdomain_result["ok"]:
        return []

    findings = []
    for item in subdomain_result["data"].get("subdomains", []):
        hostname = item.get("subdomain", "").lower()
        first_label = hostname.split(".", 1)[0]
        if any(term in first_label for term in SUBDOMAIN_REVIEW_TERMS):
            findings.append(hostname)
    return findings


def score_vendor(domain_data):
    score = 0
    findings = []

    whois = domain_data.get("whois", {}).get("data", {})
    ssl = domain_data.get("ssl", {}).get("data", {})
    dns = domain_data.get("dns", {})

    expires_in = whois.get("expiration", {}).get("daysLeft")
    if expires_in is None:
        expires_in = days_until(whois.get("expires"))

    age_days = whois.get("age", {}).get("days")
    if age_days is None and whois.get("created"):
        created_days_until = days_until(whois.get("created"))
        if created_days_until is not None:
            age_days = abs(created_days_until)

    if expires_in is not None and expires_in < 30:
        score += 25
        findings.append("Domain expires in less than 30 days")

    if age_days is not None and age_days < 90:
        score += 25
        findings.append("Domain was created less than 90 days ago")

    dmarc_txt = first_txt(dns.get("DMARC", {}).get("data"))
    if not dmarc_txt:
        score += 20
        findings.append("No DMARC record found")
    elif "p=none" in dmarc_txt.lower():
        score += 10
        findings.append("DMARC policy is p=none")

    spf_txt = first_txt(dns.get("SPF", {}).get("data") or dns.get("TXT", {}).get("data"))
    if spf_txt and ("+all" in spf_txt.lower() or " ip4:0.0.0.0/0" in spf_txt.lower()):
        score += 15
        findings.append("SPF appears too permissive")

    ssl_expires_in = days_until(ssl.get("valid_to"))
    if ssl_expires_in is not None and ssl_expires_in < 14:
        score += 20
        findings.append("SSL certificate expires in less than 14 days")

    suspicious_subdomains = domain_data.get("suspicious_subdomains", [])
    if suspicious_subdomains:
        score += 30
        findings.append("Suspicious or exposed subdomain found")

    risk_level = "low"
    if score >= 70:
        risk_level = "high"
    elif score >= 35:
        risk_level = "medium"

    return {
        "score": score,
        "risk_level": risk_level,
        "findings": findings,
    }


def audit_domain(domain):
    dns_checks = {
        "A": get_dns(domain, "A"),
        "AAAA": get_dns(domain, "AAAA"),
        "CNAME": get_dns(domain, "CNAME"),
        "MX": get_dns(domain, "MX"),
        "TXT": get_dns(domain, "TXT"),
        "DMARC": get_dns(domain, "DMARC"),
        "CAA": get_dns(domain, "CAA"),
        "MTASTS": get_dns(domain, "MTASTS"),
        "TLSRPT": get_dns(domain, "TLSRPT"),
    }
    subdomains = get_subdomains(domain)
    suspicious_subdomains = find_suspicious_subdomains(subdomains)

    domain_data = {
        "domain": domain,
        "whois": get_whois(domain),
        "dns": dns_checks,
        "ssl": get_ssl(domain),
        "subdomains": subdomains,
        "suspicious_subdomains": suspicious_subdomains,
    }
    score = score_vendor(domain_data)

    return {
        "domain": domain,
        "risk_score": score["score"],
        "risk_level": score["risk_level"],
        "findings": score["findings"],
        "summary": {
            "whois_ok": domain_data["whois"]["ok"],
            "dns_ok": dns_cache.get(domain, {}).get("ok", False),
            "ssl_ok": domain_data["ssl"]["ok"],
            "subdomains_ok": subdomains["ok"],
            "suspicious_subdomains": suspicious_subdomains,
        },
    }


if __name__ == "__main__":
    domains = ["vendor-example.com", "example-saas.io"]
    results = [audit_domain(domain) for domain in domains]
    print(json.dumps(results, indent=2, sort_keys=True))

What to Check Before Approving a Vendor

  • WHOIS/RDAP checked.
  • DNS checked.
  • Email security checked.
  • SSL checked.
  • Subdomains reviewed.
  • Monitoring enabled.
  • Risk score documented.
  • Owner assigned.

The owner matters. A vendor risk finding without an owner becomes background noise. Assign ownership to security, procurement, IT, product engineering, or the business system owner before approval.

Continuous Monitoring After Vendor Approval

The initial audit is a snapshot. Vendor infrastructure changes during renewals, migrations, acquisitions, incident response, and product launches. A vendor that passed in January may look different in May.

Monitor for changes in:

  • Expiration date and days remaining.
  • Registrar.
  • Nameservers.
  • MX provider.
  • DMARC record and policy.
  • SSL expiration and certificate replacement.
  • New subdomains.
  • Domain availability for relevant lookalikes when the vendor brand or integration is high risk. This is a narrow companion check, not a full phishing domain detection program.

The monitoring cadence should match vendor criticality. A payroll provider, SSO-connected SaaS, payment processor, or customer data processor deserves more frequent review than a low-risk content tool. Use domain monitoring for post-approval change detection instead of relying on a one-time onboarding snapshot.

Common Mistakes

  • Checking only the homepage. The risky infrastructure may be on login, API, auth, dashboard, mail, or staging hosts.
  • Trusting SSL as a security signal by itself. A valid certificate does not prove domain legitimacy.
  • Ignoring email security records. SPF, DKIM, DMARC, MTA-STS, and TLS-RPT matter when vendors send or receive sensitive mail.
  • Checking once and never again. Vendor domains change after approval.
  • Treating all vendors equally. Match depth and cadence to data access, SSO access, frontend exposure, and business criticality.
  • Not keeping an audit trail. Store inputs, results, timestamps, scores, exceptions, and owners.

FAQ

What is a vendor domain security audit?

A vendor domain security audit checks public domain signals such as WHOIS, RDAP, DNS, email security records, SSL certificates, subdomains, and monitoring events before or after vendor approval.

Is a domain audit the same as a vendor penetration test?

No. It is an automated public-signal review, not an authenticated test of the vendor's applications or internal systems.

Which DNS records matter most for vendor due diligence?

A, AAAA, CNAME, MX, TXT, SPF, DKIM, DMARC, CAA, MTA-STS, and TLS-RPT are the most useful starting points.

Why should vendor domains be monitored after approval?

Domain expiration, registrar changes, nameserver changes, MX changes, DMARC changes, SSL renewals, and new subdomains can all appear after onboarding.

Can APIs automate third-party domain risk checks?

Yes. WHOIS/RDAP, DNS lookup, SSL certificate, subdomain discovery, and monitoring APIs can be combined into a repeatable vendor risk workflow.

Conclusion

Vendor domain security is public, automatable, and too often ignored. WHOIS, RDAP, DNS, SSL, email security records, subdomain discovery, and monitoring give teams a practical vendor risk workflow before and after onboarding.

This workflow will not answer every security question about a vendor. It will answer whether the vendor's public domain posture is stable enough for the trust you plan to grant, whether obvious issues need remediation, and whether changes after approval will be noticed.

Start with 1,000 free API requests and build your first vendor domain audit workflow with WhoisJSON.

Get Your Free API KeyAPI Documentation
Vendor Risk Workflow

Automate Vendor Domain Checks

Query WHOIS, DNS, SSL, subdomain, and monitoring signals before and after vendor onboarding.

WHOIS and RDAP signalsDNS and email security checksSSL and subdomain review1,000 free requests/month
Get Free API KeyAPI Documentation