Domain Discovery
Domain discovery (stage 1, domain_enumeration) turns a brand’s owned domains and keywords into candidate lookalike domains. It is powered by dnstwist-based permutation in domain_intel/domain_generation.py.
Inputs
Section titled “Inputs”- Owned domains — the exact domains the brand controls (seeds).
- Keywords — user-provided plus AI-inferred brand keywords.
Generation families
Section titled “Generation families”The domain_generation module produces variations across several fuzzers:
| Fuzzer | Example |
|---|---|
| Typosquat | oktoboo.co (dropped character) |
| Homoglyph | oktоboot.com (lookalike unicode) |
| TLD abuse | oktoboot.org, oktoboot.net |
| Keyword variants | oktoboot-wallet.com, oktobootsupport.com |
| Character insertion / transposition | okktoboot.com, oktbooot.com |
Results are deduplicated (dedupe_findings) and collapsed across target domains so the same lookalike found for several owned domains appears once (_dedupe_across_targets).
Output
Section titled “Output”The phase returns (results, total_permutations) where results maps each owned domain to its list of DomainFinding objects, and total_permutations is the count of generated variations (used for the processed/total progress display).
def domain_enumeration_phase( domains: list[str], keywords: list[str], cancel_event=None, scan_id=None,) -> tuple[dict[str, list[DomainFinding]], int]Cancellation and dedup
Section titled “Cancellation and dedup”- The loop checks the cancel event per domain; a cancelled scan stops generating new permutations.
- Findings carry
fuzzerandoriginal_domainmetadata so the dashboard can show which family and source produced them.
Enrichment of owned domains
Section titled “Enrichment of owned domains”Outside scans, each owned domain in the brand profile triggers EnrichDomainJob → POST /v1/domain/enrich, which builds a domain_profiles snapshot. This snapshot is included in the scan-start payload so the pipeline can enrich discovered lookalikes against a fresh baseline.
- Discovery is fully deterministic and offline (no external calls) — only enrichment and scoring touch the network.
- Tests stub
dnstwist.run(seestub_dnstwistfixture inservices/tests/conftest.py).