---
title: "Discussion on \"Spot Lookalike Phishing Domains in Python: Punycode, Homoglyphs and Typos in ~140 Lines of Stdlib\" | Hashnode"
description: "Discussion on \"Spot Lookalike Phishing Domains in Python: Punycode, Homoglyphs and Typos in ~140 Lines of Stdlib\". Decode xn-- labels, catch mixed Cyrillic/Latin names, compare \"skeletons\" against a watchlist and fail CI on a hit, with a tested script and unit tests"
url: "https://hashnode.com/posts/spot-lookalike-phishing-domains-in-python-punycode-homoglyphs-and-typos-in-140-lines-of-stdlib/6aea881fb1a847fe28b58ed4"
---

[Feed](https://hashnode.com/feed) /

Discussion

# [Spot Lookalike Phishing Domains in Python: Punycode, Homoglyphs and Typos in ~140 Lines of Stdlib](https://jadenvo259.hashnode.dev/spot-lookalike-phishing-domains-in-python-punycode-homoglyphs-and-typos-in-140-lines-of-stdlib?utm_source=hashnode&utm_medium=feed)

Decode xn-- labels, catch mixed Cyrillic/Latin names, compare "skeletons" against a watchlist and fail CI on a hit, with a tested script and unit tests

Nov 4 · 9 min read · jadenvo259.hashnode.dev  
Read the article

-   [#phishing](https://hashnode.com/tag/phishing)
-   [#unicode](https://hashnode.com/tag/unicode)
-   [#tutorial](https://hashnode.com/tag/tutorial)
-   [#python](https://hashnode.com/tag/python)
-   [#security](https://hashnode.com/tag/security)

## Written by

[Jaden Vo](https://hashnode.com/@jadenvo259)

@jadenvo259

  
[View profile](https://hashnode.com/@jadenvo259)

## Responses 2

Markdown supported · ⌘↵ to post

[Furqan Ashraf](https://hashnode.com/@jfreaks)

[17h ago](https://hashnode.com/posts/spot-lookalike-phishing-domains-in-python-punycode-homoglyphs-and-typos-in-140-lines-of-stdlib/6aea881fb1a847fe28b58ed4/comment/6af3f2f2fa31e6ed2f035f5c)

Rating edit-distance-1 as MEDIUM and leaving it to a human is the right call. The question for that human usually isn't "does this look like our brand", since `check()` already answered that. It's "does this name exist and do anything". A MEDIUM that isn't registered is a note for later. One registered last week with MX records and a certificate is something to act on today.

That part needs live data, so it can't sit in a stdlib-only script. For the review step you can query RDAP for the creation date (rdap.org redirects to the right registry) and run `dig MX`, or use something that bundles both. We built [Ask WhoisFreaks](https://ask.whoisfreaks.com/) for this kind of one-off question (I work on it): "is paypa1-support.com registered, and is it on any threat feed?" gets WHOIS, DNS, SSL and feed results in one answer. It's a chat tool, so for scoring every MEDIUM inside CI you'd want an API call instead.

[Damiano Bianda](https://hashnode.com/@damianobianda)

[Nov 4](https://hashnode.com/posts/spot-lookalike-phishing-domains-in-python-punycode-homoglyphs-and-typos-in-140-lines-of-stdlib/6aea881fb1a847fe28b58ed4/comment/6aeb050e1d43a1ea1ddb9dc4)

Nice build - the "skeletonize both sides" reminder is the part people usually get wrong. Two upgrade paths worth knowing for anyone extending this: first, instead of hand-maintaining the CONFUSABLES subset, the dict can be generated at build time from the official confusables data file behind UTS #39 - the full table covers thousands of entries, including Armenian and Cherokee lookalikes that a hand-picked Cyrillic/Greek subset misses, and the runtime stays stdlib-only. Second, this checker gets much more powerful pointed at a live feed: running it against newly issued certificate names from Certificate Transparency logs is a common way to catch lookalike registrations of your own brand within hours, before the domain ever sends a single phishing email. The exit-code-per-batch design makes that an easy cron job. Rating edit distance 1 as MEDIUM is also the right call - short brand labels have too many legitimate neighbors for auto-blocking.
