▸ How to find typosquatting domains
Generating lookalike domains is the easy half. Finding which ones somebody actually registered, and which of those are a real threat, is the half that matters. Every working method, with the commands and the triage rules.
▸ The short answer
Generate permutations of your brand, then check them against a corpus of domains already known to exist instead of sending a DNS query per candidate. Rank whatever survives by three fields: MX record, A record, TLS certificate. Those three separate the handful worth acting on from the several hundred parked strings that are not.
- ▸ One-off audit of a brand you own? dnstwist plus a corpus lookup. An afternoon, no budget.
- ▸ Continuous detection? Screen the daily new-domain feed against your permutation list, and tail Certificate Transparency. Catch a registration on the day it happens, not on the day it is used against you.
- ▸ Deciding what to escalate? Start from your own resolver logs. A lookalike nobody in your organisation has ever resolved ranks below one that ten people hit last week.
| approach | what it catches | speed | cost | effort |
|---|---|---|---|---|
| Permutation generation (dnstwist, urlcrazy) | Classic misspellings of a name you already know | On demand | Free | Medium |
| Search a registered-domain corpus | Any registered name containing your brand, combosquats included | Instant | Free | Low |
| Certificate Transparency monitoring | Lookalikes seconds after they get a TLS certificate | Seconds to minutes | Free | Medium |
| Screen a daily new-domain feed | Everything registered yesterday, filtered by your own rules | Daily | Free | Medium |
| Your own resolver logs + passive DNS | The lookalikes your staff and customers are actually hitting | Hours | Free to paid | Medium |
| Commercial brand protection | Broad coverage, with takedown handled for you | Daily | Paid | Low |
| TMCH trademark claims | Exact-match registrations in new gTLDs, at registration time | At registration | Paid (annual) | Low |
▸ Typosquatting, and the four other things called typosquatting
Typosquatting in the strict sense is registering a domain a human reaches by mistyping yours. In practice five distinct families get filed under the one word, and they need different detection methods - a permutation generator finds the first two and is blind to the rest:
- 1. Typosquatting - a keyboard-distance mistake.
exapmle.com,exmple.com,examlpe.com. Found by permutation generation. - 2. TLD squatting - the same string under another suffix.
example.co,example.cm,example.app. Also permutation, but you have to supply the TLD list. - 3. Combosquatting - your brand spelled correctly, plus a word.
example-login.com,secure-example.net,example-support.co. The most common family in real phishing, and no typo generator produces it. Only substring search over registered domains finds it. - 4. Homograph / IDN spoofing - characters that render alike. Cyrillic
afor Latina,rnform,1forl. Stored as punycode (xn--), so a byte comparison against your brand never flags them. - 5. Bitsquatting - a single flipped bit in the name as it sits in memory or in transit.
fxample.comforexample.com. Rare, real, and cheap to generate.
evil.com and serves example.com.login.evil.com. No amount of registration monitoring finds it, because nothing new was registered. Certificate Transparency and your own log analysis are the only things that will.▸ Generate the candidate set
dnstwist is the reference implementation and what nearly everyone ends up running. It applies every permutation family in one pass - omission, insertion, repetition, transposition, keyboard-adjacent replacement, vowel swap, hyphenation, homoglyph, bitsquatting - and can optionally check which candidates resolve. urlcrazy ships with Kali and does the same job with a different word list.
Three ways to run it, cheapest first:
# 1. Permutations only, no network - this is your candidate list dnstwist --format list example.com > candidates.txt wc -l candidates.txt # 2. Same sweep, but resolve as it goes and keep only what exists dnstwist --registered --format csv example.com > registered.csv # 3. The two fields that decide priority later: MX, and a fuzzy hash of the # live page compared against the real one (--ssdeep on older builds) dnstwist --registered --mx --lsh ssdeep --format json example.com > registered.json # 4. Cross the brand with a TLD dictionary, not just the suffix you own printf '%s\n' com net org co io app shop online site xyz > tlds.txt dnstwist --tld tlds.txt --format list example.com | sort -u > candidates.txt
A single token like example produces roughly one to three thousand permutations before you add TLDs. Cross that with a TLD list and you are at tens of thousands of candidates, which is exactly why the next step is not “resolve them all”.
example.com also permutes .com, which is noise; permuting example and crossing it with a TLD list you chose gives you a set you can reason about. Pick the TLDs abused in your sector, not all 1,400.▸ Turn candidates into confirmed registrations
You now hold thousands of strings and no idea which exist. Four ways to find out, and three are worse than they look:
- ▸ DNS resolution - fast and free, but it only proves the name has an A or NS record. A registered domain with no name servers resolves to nothing and you will miss it, and negative caching can keep returning NXDOMAIN for the length of the SOA minimum.
- ▸ RDAP or WHOIS per candidate - authoritative, and rate-limited per registry to the point where 20,000 candidates is a multi-day job. Use it on the shortlist, never on the candidate set.
- ▸ Zone-file grep - accurate for the gTLDs you hold CZDS approval for, several gigabytes per zone, blind to nearly every ccTLD.
- ▸ Look the candidates up in an existing corpus - one query instead of thousands, no rate limit, and coverage of TLDs you have no zone access to. That is the next section.
Example.CO.UK. and example.co.uk are one finding, and counting dots to locate the registrable part is how foo.co.uk gets mis-parsed.▸ Search a corpus of registered domains
This is the site you are on, so weigh the section accordingly. It belongs here because of the shape of the problem: DNSniffer indexes gTLD zone files and Certificate Transparency across every TLD into one searchable domain table - currently 358,047,798 active domains across 9,957 TLDs, the search endpoint is public and needs no account, and it takes wildcards. So instead of asking “does this candidate exist?” twenty thousand times, you ask “what exists that looks like this?” once.
The wildcard is the part that matters here: * matches any run of characters, so exam*le catches insertions, deletions and substitutions in the middle of the token in a single query.
# 1. Every indexed domain containing your brand string, any TLD
curl -s 'https://dnsniffer.com/api/v1/domains?q=example&limit=1000' \
| jq -r '.data[].name'
# 2. "*" is a wildcard, so one query covers a missing, extra or swapped
# character anywhere in the middle of the token
curl -s 'https://dnsniffer.com/api/v1/domains?q=exam*le&limit=1000' \
| jq -r '.data[] | [.name, .tld, .cert_issuer.organization // "-"] | @tsv'
# 3. Narrow to one TLD
curl -s 'https://dnsniffer.com/api/v1/domains?q=example&tld=com&limit=1000'
# 4. Screen today's new domains against the candidate list from step 1
URL=$(curl -s 'https://dnsniffer.com/api/v1/datasets?category=newly_detected' \
| jq -r '.data[] | select(.periodicity=="daily") | .download_url')
curl -sL "https://dnsniffer.com$URL" -o nrd-daily.zip
unzip -p nrd-daily.zip | tail -n +2 | cut -d, -f1 | sort -u > today.txt
comm -12 today.txt <(sort -u candidates.txt) > hits.txtTwo limits to know before you lean on it. The corpus is built from observations - zone delegation and certificate issuance - so a registered domain that was never delegated and never certified is not in it. And a hit tells you the name exists, not when it was registered; verify anything you act on with RDAP.
For continuous detection rather than a one-off audit, two things run server-side. The monitor holds up to ten substring watches per account and emails a digest when newly indexed domains match one. The newly-detected exports give you every domain indexed in the last 24 hours as a CSV, which is what you run your permutation list against. The newest domains page is the same stream in a browser.
example-login.com and misses exarnple.com, because the second one does not contain your string. Watches cover the combosquat family; the typo family still needs your generated list run against the daily feed.▸ Catch them at certificate issuance
A lookalike becomes dangerous when it starts serving a page, and nearly every phishing page is served over HTTPS - which means a certificate, which means a public Certificate Transparency entry seconds after issuance. CT is the only method here that tells you about a lookalike before the first victim reaches it, and the only one that sees subdomain spoofing.
Two ways in: consume an aggregated firehose, or read the logs directly over the RFC 6962 API. Either way you write the filter yourself, and the filter is where fuzzy matching belongs - you are watching a stream of names rather than testing a fixed candidate list.
# Aggregated firehose, filtered to names close to your brand
websocat wss://certstream.calidog.io \
| jq -r '.data.leaf_cert.all_domains[]?' \
| sed 's/^\*\.//' \
| python3 -c '
import sys, unicodedata, idna
from rapidfuzz.distance import Levenshtein
BRAND = "example"
def decode(name):
try:
return idna.decode(name) if "xn--" in name else name
except Exception:
return name
def fold(s):
# Cheap confusable folding. A real one uses the Unicode confusables table.
s = unicodedata.normalize("NFKD", s)
for a, b in (("rn", "m"), ("vv", "w"), ("1", "l"), ("0", "o"), ("5", "s")):
s = s.replace(a, b)
return s
for line in sys.stdin:
name = line.strip().lower()
label = fold(decode(name)).split(".")[0]
if BRAND in label: # combosquat
print("substring", name, flush=True)
elif Levenshtein.distance(label, BRAND) <= 2: # typo / homoglyph
print("distance ", name, flush=True)
'Certificates carry SANs, so one certificate yields many names. Collapse each to the registrable domain, then run three tests, because each is blind to what the others catch: edit distance of 2 or less against your brand token finds the typo family, a plain substring test finds the combosquat family, and decoding xn-- labels before normalising confusables finds the homograph family.
▸ Read your own DNS logs first
Everything above finds lookalikes that exist. Your resolver logs find lookalikes that work, which is a far shorter and far more urgent list. Two queries against your DNS or proxy logs are worth more than most paid feeds:
- ▸ NXDOMAIN answers that are near-misses on your own domain. That is your own staff and customers mistyping it. Each one is a name somebody can register tomorrow and start collecting misdirected mail on. Registering the top of that list yourself is the cheapest control on this page.
- ▸ Successful resolutions of names close to yours that you do not own. Somebody inside your network is reaching a lookalike right now. That is an incident, not a monitoring finding.
# Unbound / BIND query log -> names your users typed that do not exist,
# ranked by how many times they typed them
grep NXDOMAIN /var/log/unbound/query.log \
| awk '{print tolower($NF)}' \
| python3 -c '
import sys
from rapidfuzz.distance import Levenshtein
for name in sys.stdin:
name = name.strip().rstrip(".")
label = name.split(".")[0]
if 0 < Levenshtein.distance(label, "example") <= 2:
print(name)
' | sort | uniq -c | sort -rn | head -20Passive DNS extends the same idea past your perimeter: providers record resolutions seen by cooperating recursive resolvers and give you a first-seen timestamp per name. Useful for establishing when a lookalike went live, and biased by construction, since you only see what their sensor network sees.
▸ Paid help, takedown and arbitration
Brand protection vendors - MarkMonitor, CSC, ZeroFox, Bolster and a long tail of others - sell lookalike monitoring bundled with takedown execution. The monitoring is not the hard part, and the five sections above reproduce most of it. What you are buying is the second half: standing relationships with registrars and hosting providers, abuse reports filed and chased. If nobody on your team has a Tuesday afternoon to spend arguing with a registrar in another jurisdiction, that is worth real money.
Four routes once you have a confirmed abusive domain, fastest and cheapest first:
- 1. Registrar and host abuse reports - free, and by far the fastest for an active phishing site. Send evidence to the registrar's abuse contact and the hosting provider's in parallel: URL, screenshots, timestamps, what it impersonates. A live credential-harvesting page can come down in hours. A parked lookalike gets ignored.
- 2. Blocklist submissions - Google Safe Browsing, APWG, PhishTank and your own EDR or DNS filter. This protects your users within minutes while everything else runs on legal time.
- 3. URS - from roughly USD 375, decided in weeks. It only suspends the domain for the remainder of its registration term; it does not transfer it to you, and it demands clear and convincing evidence. Good for unambiguous phishing, useless for anything arguable.
- 4. UDRP - roughly USD 1,500 in provider fees for a single-panellist case covering a few domains, plus counsel, plus a couple of months. It transfers the name to you. You must show all three elements: confusing similarity to your mark, no legitimate interest on the registrant's side, and registration and use in bad faith.
example-login does not trigger it.▸ Rank what you found
A permutation sweep of a recognisable brand routinely returns several hundred registered lookalikes. Almost all are parked, and chasing all of them is how a brand protection programme dies. Rank on evidence of operation, strongest signal first:
- ▸ MX record present. The domain can receive mail. This is the top of the list every time - it is how invoice fraud and business email compromise start, and it needs no website at all.
- ▸ A record pointing at a live HTTP service. Fetch it. A registrar parking page is noise; a copy of your login form is an incident.
- ▸ Certificate issued. Somebody configured something. Free DV certificates make this weak evidence alone and strong evidence combined with an A record.
- ▸ Page similarity. Compare a fuzzy hash of the rendered page, or just the favicon hash, against your own.
dnstwist --lshdoes the first for you; a favicon hash match is crude and startlingly effective. - ▸ Registration age and registrar. Registered last week at a registrar with a poor abuse record is a different risk from a name somebody has held since 2013. This is the point where RDAP verification earns its rate limits.
- ▸ Resolved by anyone you care about. Cross-reference against your resolver logs. That turns a monitoring hit into a ticket with a blast radius.
# Rank confirmed lookalikes by how operational they are
while read -r d; do
a=$(dig +short A "$d" | head -1)
mx=$(dig +short MX "$d" | head -1)
[ -n "$a$mx" ] && printf '%s\tA=%s\tMX=%s\n' "$d" "${a:--}" "${mx:--}"
done < hits.txt | sort -t= -k3 -r
# Authoritative registration date for the shortlist only - RDAP rate-limits
while read -r d; do
curl -s "https://rdap.org/domain/$d" \
| jq -r --arg d "$d" '.events[]? | select(.eventAction=="registration")
| "\($d),\(.eventDate)"'
sleep 1
done < shortlist.txt > shortlist-dates.csv▸ What makes a lookalike sweep wrong
- ▸ Measuring distance against punycode.
xn--exmple-4of.comis nowhere nearexample.comas bytes and identical to it on screen. Decode everyxn--label before you compare anything. - ▸ Trusting NXDOMAIN. A registered domain with no name servers does not resolve. Absence of a DNS answer is not absence of a registration.
- ▸ Counting dots to find the registrable domain.
foo.co.ukandfoo.ukfollow different rules. Use the Public Suffix List. - ▸ Only generating, never searching. No permutation generator will produce
example-account-verify.com. Skip the substring search over registered domains and the entire combosquat family is invisible to you - and that is the family that turns up in real phishing. - ▸ Re-alerting on renewals. Without a permanent first-seen set, every certificate renewal looks like a fresh discovery and your queue fills with domains you triaged in March.
- ▸ Defensive registration without a plan. Buying the top fifty typos is sensible; buying five thousand is a recurring bill with no exit, and the permutation space is effectively infinite. Register what your own NXDOMAIN logs prove people actually type, redirect those to your real site, and leave the rest to monitoring.
▸ Frequently asked questions
? What is typosquatting?
Registering a domain that people reach by mistyping a real one - exapmle.com for example.com. Intent varies: some typosquatters serve ads and monetise the stray traffic, some redirect to competitors, some hold the name to resell it to the brand, and some run phishing pages or intercept email sent to the misspelled address. The technique is old and still works, because the failure it exploits is human rather than technical.
? How do I find typosquatting domains for my brand?
Two passes, and you need both. First, generate permutations of your brand token with dnstwist or urlcrazy and find out which are registered - that covers the typo, TLD-swap and homoglyph families. Second, search a corpus of registered domains for your brand as a substring, which covers the combosquat family that no generator can produce. Then rank the hits by MX record, A record and certificate, and verify registration dates with RDAP only for the shortlist you intend to act on.
? Is typosquatting illegal?
It depends on intent and jurisdiction, which is why arbitration exists rather than a blanket rule. In the United States the Anticybersquatting Consumer Protection Act makes registering a domain confusingly similar to a distinctive mark, with bad-faith intent to profit, actionable. Internationally, UDRP requires all three of: confusing similarity to your mark, no legitimate interest on the registrant's part, and registration and use in bad faith. Registering a name that merely resembles a common word is not by itself unlawful.
? What is the difference between typosquatting, combosquatting and cybersquatting?
Cybersquatting is the umbrella term for registering a domain in bad faith to exploit somebody else's mark. Typosquatting is the subset that relies on a misspelling. Combosquatting spells your brand correctly and adds a word - example-support.com, example-login.net - and it is both more common in real phishing and harder to detect, because the brand string is correct and the number of words you can append is unlimited.
? How many typo domains should I register defensively?
Fewer than a vendor will tell you. The set with a real return is small: the two or three most frequent misspellings, your brand under the handful of TLDs customers assume you use, and any name your own NXDOMAIN logs show people actually typing. Point them at your real site and monitor everything else. Defensive registration is a recurring annual cost per name against a permutation space that is effectively infinite - you cannot buy your way out of it.
? What is a homograph attack and how do I detect one?
Substituting characters that render alike - a Cyrillic a for a Latin a, a Greek omicron for an o, the pair rn for m. The name is stored as punycode, so it begins with xn-- and a byte comparison against your brand finds nothing. Detection means decoding every xn-- label, normalising confusable characters to a canonical form using the Unicode confusables mapping or a hand-built table for the common substitutions, and only then measuring similarity. Browsers mitigate the display side by showing punycode when a label mixes scripts, but that does nothing for your monitoring.
? How do I get a typosquatted domain taken down?
Fastest first. If it is actively phishing, report it to the registrar's abuse address and the hosting provider at the same time with screenshots, the URL, timestamps and what it impersonates; that can resolve in hours and costs nothing. Submit it to Google Safe Browsing and the phishing blocklists in parallel, which protects your users while everything else runs on legal time. If you want the name rather than its removal, file a UDRP: about USD 1,500 in provider fees plus counsel and a couple of months, and it transfers the domain to you. URS is cheaper and faster but only suspends the domain until its registration expires.
? Can I monitor for new typosquatting domains for free?
Yes, and it is mostly a scheduling problem. Tail the Certificate Transparency logs and run your similarity filter over the names, which costs one small always-on process. Or download a daily newly-detected domains export and run your permutation list and substring rules against it once a day, which is a cron job. DNSniffer publishes both the daily export and a public search API with no account, and free accounts get up to ten substring watches with an email digest. Pay for commercial brand protection when you need the takedown work done, not when you need the detection.
Screening a daily feed against your own permutation list is a cron job, not a project. The newly-detected exports are rebuilt every day and free to download - 463,220 domains in the current 24-hour file, and the domain search takes wildcards without an account.