Introduction
Domain hijacking is not the same as phishing a lookalike brand or finding a newly registered typo. Hijacking means an attacker takes control of a domain you already own — or that your customers trust as yours — by transferring the registration, changing DNS delegation, or swapping the TLS certificate that terminates traffic.
Because GDPR and privacy proxies often hide registrant contacts, ownership identity is a weak detection surface. The reliable signals live in the control plane: EPP transfer locks, registrar of record, nameservers, live DNS answers and certificate fingerprints.
This guide builds a detection workflow on the WHOIS API, DNS lookup API and SSL certificate API. It complements brand protection (lookalikes) and phishing detection (adversary infrastructure), without replacing the EPP status reference.
Domain Hijacking vs Phishing vs Typosquatting
| Threat | What changes | Primary detection focus |
|---|---|---|
| Domain hijacking | Control of an existing domain (transfer, NS, cert) | Baseline drift on your own assets |
| Typosquatting / brand abuse | New lookalike domains registered by others | Similarity search + NRD + enrichment |
| Phishing infrastructure | Fresh domains built to impersonate | Age, opacity, DNS/SSL weaponization signals |
Common Hijack Paths
- Unauthorized registrar transfer after social engineering, account takeover or expired transfer lock
- Nameserver rewrite at the registrar while the domain remains “registered to you” on paper
- DNS record hijack (A/AAAA/CNAME) pointing traffic to attacker infrastructure
- TLS certificate replacement so browsers still show a “valid” lock on a malicious origin
- Post-expiry recovery races when redemption and pendingDelete windows are mishandled
Expiry lifecycle detail lives in what happens when a domain expires. Here the focus is detecting unauthorized control changes while the domain is still supposed to be yours.
Detection Signals That Still Work
When contacts are redacted, treat these fields as your hijack sensor set. Store a baseline, then compare every poll.
EPP transfer lock
clientTransferProhibited / serverTransferProhibited removed unexpectedly is a high-severity alert.
Registrar drift
registrar.name or registrar.id changing without a planned migration.
Nameserver drift
WHOIS nameserver list diverging from your approved DNS provider set.
Live DNS drift
NS, A/AAAA or critical CNAME answers changing outside a change window.
SSL fingerprint swap
details.fingerprint256 changing without a known renewal or ACME rotation.
Combined severity
Lock removal + NS change + cert change in the same window is almost always an incident.
Build a Domain Control Baseline
Hijack detection is change detection. Without a baseline, every lookup is just a snapshot.
{
"domain": "example.com",
"capturedAt": "2026-08-26T10:00:00Z",
"registrar": "Example Registrar, Inc.",
"status": ["clientTransferProhibited", "clientUpdateProhibited"],
"transferLocked": true,
"nameservers": ["ns1.approved-dns.com", "ns2.approved-dns.com"],
"aRecords": ["203.0.113.10"],
"fingerprint256": "85:70:14:19:D2:F6:ED:7A:..."
}Prefer RDAP-enriched statusAnalysis when present for lock interpretation, and keep raw status arrays for audit. See working with redacted WHOIS for why contact fields should not be part of the baseline identity model.
Query the Three Layers
Authenticate every call with Authorization: TOKEN=YOUR_API_KEY.
curl "https://whoisjson.com/api/v1/whois?domain=example.com" \
-H "Authorization: TOKEN=YOUR_API_KEY"curl "https://whoisjson.com/api/v1/nslookup?domain=example.com" \
-H "Authorization: TOKEN=YOUR_API_KEY"curl "https://whoisjson.com/api/v1/ssl-cert-check?domain=example.com" \
-H "Authorization: TOKEN=YOUR_API_KEY"A minimum viable check is three requests per domain. Critical customer-facing hostnames may need additional SSL checks for code www | or login subdomains.
Severity Model
| Finding | Suggested severity | Typical response |
|---|---|---|
| Transfer lock removed only | High | Verify registrar account MFA and recent auth events immediately |
| Registrar changed | Critical | Incident bridge; confirm whether a transfer was authorized |
| WHOIS NS changed | Critical | Freeze DNS changes; compare with live NS lookup |
| Live A/AAAA changed | High / Critical | Check CDN cutovers vs malicious hosting; review access logs |
| SSL fingerprint changed | Medium / High | Correlate with ACME renewals; escalate if paired with DNS drift |
| Lock + NS + cert in same poll | Critical | Assume compromise until proven otherwise |
Python Detection Pipeline
Compare a stored baseline with live WHOIS, DNS and SSL responses and emit structured findings.
import requests
API_KEY = "YOUR_API_KEY"
HEADERS = {"Authorization": f"TOKEN={API_KEY}"}
BASE = "https://whoisjson.com/api/v1"
def get_json(path, domain):
r = requests.get(
f"{BASE}/{path}",
params={"domain": domain},
headers=HEADERS,
timeout=30,
)
r.raise_for_status()
return r.json()
def norm_ns(values):
return sorted({(v or "").rstrip(".").lower() for v in (values or []) if v})
def transfer_locked(status, analysis):
analysis = analysis or {}
if "transferLocked" in analysis:
return bool(analysis["transferLocked"])
status = [s.lower() for s in (status or [])]
return any("transferprohibited" in s for s in status)
def detect_hijack(domain, baseline):
whois = get_json("whois", domain)
dns = get_json("nslookup", domain)
ssl = get_json("ssl-cert-check", domain)
findings = []
registrar = (whois.get("registrar") or {}).get("name")
locked = transfer_locked(whois.get("status"), whois.get("statusAnalysis"))
whois_ns = norm_ns(whois.get("nameserver"))
live_ns = norm_ns(dns.get("NS"))
live_a = sorted(dns.get("A") or [])
fp = (ssl.get("details") or {}).get("fingerprint256")
if baseline.get("transferLocked") and not locked:
findings.append({"signal": "transfer_lock_removed", "severity": "high"})
if registrar and registrar != baseline.get("registrar"):
findings.append({
"signal": "registrar_changed",
"severity": "critical",
"from": baseline.get("registrar"),
"to": registrar,
})
if whois_ns and whois_ns != norm_ns(baseline.get("nameservers")):
findings.append({"signal": "whois_nameserver_changed", "severity": "critical"})
if live_ns and whois_ns and live_ns != whois_ns:
findings.append({"signal": "whois_vs_live_ns_mismatch", "severity": "high"})
if live_a and live_a != sorted(baseline.get("aRecords") or []):
findings.append({"signal": "a_record_changed", "severity": "high"})
if fp and fp != baseline.get("fingerprint256"):
findings.append({"signal": "ssl_fingerprint_changed", "severity": "medium"})
critical = sum(1 for f in findings if f["severity"] == "critical")
if critical >= 2:
findings.append({"signal": "multi_signal_compromise", "severity": "critical"})
return {
"domain": domain,
"findings": findings,
"alert": any(f["severity"] in ("high", "critical") for f in findings),
}
baseline = {
"registrar": "Example Registrar, Inc.",
"transferLocked": True,
"nameservers": ["ns1.approved-dns.com", "ns2.approved-dns.com"],
"aRecords": ["203.0.113.10"],
"fingerprint256": "85:70:14:19:D2:F6:ED:7A:...",
}
print(detect_hijack("example.com", baseline))
Node.js Detection Pipeline
Same three-layer comparison using native code fetch | .
const API_KEY = "YOUR_API_KEY";
const HEADERS = { Authorization: `TOKEN=${API_KEY}` };
const BASE = "https://whoisjson.com/api/v1";
async function getJson(path, domain) {
const url = new URL(`${BASE}/${path}`);
url.searchParams.set("domain", domain);
const res = await fetch(url, { headers: HEADERS });
if (!res.ok) throw new Error(`${path} failed: ${res.status}`);
return res.json();
}
const normNs = (values = []) =>
[...new Set(values.filter(Boolean).map((v) => String(v).replace(/\.$/, "").toLower()))].sort();
function transferLocked(status = [], analysis = {}) {
if (Object.prototype.hasOwnProperty.call(analysis, "transferLocked")) {
return Boolean(analysis.transferLocked);
}
return status.some((s) => String(s).toLowerCase().includes("transferprohibited"));
}
async function detectHijack(domain, baseline) {
const [whois, dns, ssl] = await Promise.all([
getJson("whois", domain),
getJson("nslookup", domain),
getJson("ssl-cert-check", domain),
]);
const findings = [];
const registrar = whois.registrar?.name || null;
const locked = transferLocked(whois.status, whois.statusAnalysis);
const whoisNs = normNs(whois.nameserver);
const liveNs = normNs(dns.NS);
const liveA = [...(dns.A || [])].sort();
const fp = ssl.details?.fingerprint256 || null;
if (baseline.transferLocked && !locked) {
findings.push({ signal: "transfer_lock_removed", severity: "high" });
}
if (registrar && registrar !== baseline.registrar) {
findings.push({
signal: "registrar_changed",
severity: "critical",
from: baseline.registrar,
to: registrar,
});
}
if (whoisNs.length && JSON.stringify(whoisNs) !== JSON.stringify(normNs(baseline.nameservers))) {
findings.push({ signal: "whois_nameserver_changed", severity: "critical" });
}
if (liveNs.length && whoisNs.length && JSON.stringify(liveNs) !== JSON.stringify(whoisNs)) {
findings.push({ signal: "whois_vs_live_ns_mismatch", severity: "high" });
}
if (liveA.length && JSON.stringify(liveA) !== JSON.stringify([...(baseline.aRecords || [])].sort())) {
findings.push({ signal: "a_record_changed", severity: "high" });
}
if (fp && fp !== baseline.fingerprint256) {
findings.push({ signal: "ssl_fingerprint_changed", severity: "medium" });
}
if (findings.filter((f) => f.severity === "critical").length >= 2) {
findings.push({ signal: "multi_signal_compromise", severity: "critical" });
}
return {
domain,
findings,
alert: findings.some((f) => f.severity === "high" || f.severity === "critical"),
};
}
detectHijack("example.com", {
registrar: "Example Registrar, Inc.",
transferLocked: true,
nameservers: ["ns1.approved-dns.com", "ns2.approved-dns.com"],
aRecords: ["203.0.113.10"],
fingerprint256: "85:70:14:19:D2:F6:ED:7A:...",
}).then(console.log);
Continuous Monitoring Instead of Polling Alone
Homegrown polls work for a short list. For production portfolios, use Domain Monitoring to watch WHOIS, DNS and SSL changes and receive email alerts when something moves. Keep custom severity logic for the domains where a false negative is unacceptable — payment hosts, SSO, API gateways, marketing apex domains.
Related operational guides: domain monitoring baseline for security teams, nameserver monitoring and SSL certificate monitoring.
Incident Response Checklist
clientTransferProhibited (and update locks where appropriate) after regaining registrar access.fingerprint256 baseline.Limits and False Positives
- CDN cutovers and blue/green IP changes look like A-record hijacks without a change window
- Let’s Encrypt and other ACME renewals change fingerprints on a short cadence
- Registrar rebrands or IANA ID remaps can appear as registrar drift
- WHOIS NS and live NS can diverge briefly during DNS provider migrations
- Redacted contacts will not tell you who initiated a transfer — escalate to the registrar
Frequently Asked Questions
How do you detect domain hijacking with an API?
Baseline registrar, EPP transfer locks, nameservers, live DNS records and SSL fingerprints. Poll WHOIS, DNS and SSL endpoints, then alert on unauthorized drift — especially multi-signal changes.
Which WhoisJSON endpoints are used for hijack detection?
Use GET /api/v1/whois for registrar and status, GET /api/v1/nslookup for live DNS, and GET /api/v1/ssl-cert-check for certificate fingerprints. Domain Monitoring can alert on changes continuously.
Is removal of clientTransferProhibited always a hijack?
No. Administrators remove transfer locks before legitimate transfers. Treat unexpected removal as high severity and verify against change tickets and registrar account activity.
Can domain hijacking be detected when WHOIS contacts are redacted?
Yes. Hijack detection relies on control-plane fields — locks, registrar, nameservers, DNS and SSL — not registrant email or phone.
How is hijacking different from phishing detection?
Hijacking watches your existing domains for unauthorized control changes. Phishing detection scores someone else’s newly registered domains for weaponization risk.
How often should hijack checks run?
Critical domains often need hourly or continuous monitoring. Broader portfolio scans can run daily. Increase frequency during registrar migrations or after account security events.
Conclusion
Domain hijacking detection is baseline discipline: lock state, registrar, nameservers, live DNS and certificate fingerprints. Query WhoisJSON’s WHOIS, DNS and SSL APIs on a schedule, escalate multi-signal drift immediately, and keep Domain Monitoring on the assets you cannot afford to miss.
Detect domain control changes with WhoisJSON
Monitor WHOIS, DNS and SSL in JSON — then alert before a hijack becomes an outage or brand incident.
Start Domain MonitoringExplore WHOIS API