Takedown Evidence Package
When you've found a malicious domain, the next hurdle is proving it. This assembles a one-pass takedown package — the reputation verdict, who owns it, the abuse lists naming it, and the infrastructure around it — laid out ready to hand to a registrar or hosting provider so the takedown actually sticks.
The alert
A customer forwards a link and the host in it is ickaoex.com. explain() scores the domain 46.07 / HIGH — enough to open a case, nothing like enough to make a registrar close it.
The question
Do I file a takedown on this domain, and what would tell me I am wrong?
A score ranks the domain. A complaint has to name somebody accountable, and nothing in 46.07 / HIGH names anyone.
What this cannot answer
- What is on the page. Whisper reads infrastructure, never content.
whisper.assessreturns the sub-labelmalwarebecause a feed classified it that way; nothing in this run fetched the site. The screenshot the abuse form asks for has to come from you. - Who registered it. The WHOIS step returns nothing on this domain — run twice on 2026-08-09, and each of its four branches run separately.
whisper.historycovers part of the gap and hands backREDACTED FOR PRIVACYfor the registrant. - Where the site is served from. Both addresses the run finds are Cloudflare edge addresses. The origin is not in the graph, so the hosting half of a takedown has no addressee here.
- How current the registration record is. The stored WHOIS snapshot carries
queryTime 2026-04-09 16:48:01, three days after the domain was created, and unmoved since. - How much of the domain was actually checked. That is the coverage qualifier on
whisper.assess, and reading it comes first — Coverage.
What do we know
whisper.assess(["ickaoex.com"]) returns label: malicious, band: HIGH, sub_labels: ["malware"], and the qualifier that decides how hard you can push: coverage: malicious-evidenced, with host-class:unknown and feed-source-count:1 in its evidence array.
One source. The whole threat case is hagezi-tif-full, weight 1.50, first seen 2026-08-03, last seen 2026-08-07. explain() prints the arithmetic that turns that into a number: base 1.50 × log₂(1 + 1) = 40.00, then a recency multiplier and an age multiplier.
Which is why the dossier carries two numbers for one domain. The feed step returns the stored threatScore of 40.00; explain() returns 46.07. Those are the same score before and after the multipliers: put the arithmetic in the package, not the bare figure.
The empty WHOIS result is not a finding about the domain: zero rows is never a verdict. Here the four branches were re-run one at a time and the domain's outgoing edges enumerated — RESOLVES_TO, LISTED_IN, CHILD_OF, no registration edge. The absence survived that check, which is what makes it reportable.
Why
- 01Threat verdict. Opens the dossier with the authoritative sourced verdict that justifies pursuing a takedown at all.
- 02Threat-feed listings. Cites the specific LISTED_IN feeds (minus popularity lists) plus the score and level — third-party corroboration a registrar/host will accept.
- 03WHOIS owner, registrar & contact. Names the registrar and registrant organisation — the accountable parties and the addressees of an abuse complaint.
- 04Registration age (NRD signal). Surfaces creation date via whisper.history; a newly-registered domain is a strong abuse indicator that strengthens the case.
- 05Resolving IPs + network owner. Maps the domain to its IP, prefix and named ASN, identifying the host that abuse contact must also reach.
- 06Co-hosted domains (the wider campaign). Reverse-resolves the IP to surface co-hosted siblings — the wider campaign that should be taken down alongside the seed.
- 07Registered look-alikes. Lists existing brand variants so related squats are bundled into the same takedown rather than left to resurface.
The pivot the score did not suggest
Follow the two addresses one step further, which is what the hosting step does. 104.21.77.231 sits in 104.21.64.0/20, 172.67.212.145 in 172.67.208.0/20, and both prefixes are routed by AS13335 — CLOUDFLARENET. The two inbound NAMESERVER_FOR edges name bethany.ns.cloudflare.com and boyd.ns.cloudflare.com. Naming and transport are both proxied, so the "network owner" the run produces is a reverse proxy rather than a host.
The co-hosted step inherits that. 2091 hostnames resolve to 104.21.77.231, and 23 of them carry any feed listing at all. On a dedicated address that step finds a campaign; on a shared edge address it finds tenants — spaceify.ai, radarcovid.app, a chiropractor in South Australia.
The score contains no hint of either fact. The one accountable party the whole run produces arrives from whisper.history: registrar West263 International Limited, registrant country SG, created 2026-04-06.
Falsify it
The case rests on a single listing, so re-run the feed step before sending anything. If hagezi-tif-full drops the domain, explain() returns 0.00 / NONE and the package is empty — which is exactly what it returns today for the one look-alike this run found.
That look-alike repays a second query. whisper.variants returns one existing variant, yckaoex.com, method BITSQUATTING, confidence 1.0. It scores 0.00 / NONE and has no RESOLVES_TO edge, yet it carries the owner record the seed lacks: registrant privacy service provided by withheld for privacy ehf, plus a WHOIS phone and email. Note what its registrar field returns — iana:1068. The REGISTRAR node holds an IANA identifier, so even the working version of that step hands you a number to look up rather than a name.
Nothing in the graph joins yckaoex.com to ickaoex.com beyond the string. Bundling it into the same complaint is an assertion this run does not support. The queries, with their output, are on Threat intel.
The conclusion
ickaoex.com is filable at the registrar and nowhere else: one feed listing classified as malware, a registration dated 2026-04-06 through West263 International Limited, a redacted registrant, and every hosting-side addressee resolving to a reverse proxy. Address it to the registrar whisper.history names. Addressing it to AS13335 names a company that is not serving the content.
Four things would change that, and each is a query rather than an opinion:
- the feed step returning nothing on a later run — the entire threat case is one listing, and listings churn;
- a
HAS_REGISTRARorREGISTERED_BYedge appearing on the domain, which would give the package an owner it does not have today; - a co-hosted sibling that shares the registrar or the registrant rather than only the address, which would turn 2091 neighbours into a campaign;
yckaoex.comstarting to resolve, which would make the look-alike a second target instead of a footnote.
A registrar can check a dossier that says which of its claims are queries. It cannot check one that says HIGH.
What this cost
7 named steps across the threat-intel, DNS, WHOIS layers. The runner reports what each step returned, row by row, so the evidence and what it took to get it arrive together rather than as one number at the end.
How it uses the graph
Traverses the threat-intel, DNS, WHOIS layers of the graph, in 7 steps:
Scoring the domain with explain()…
Listing the threat feeds that name it…
Reading the WHOIS registrar and registrant…
Pulling registration history for the NRD signal…
Resolving IPs and naming the hosting network…
Finding domains sharing its IP…
Generating registered look-alike domains…