codebox/homoglyph is a confusables list turned into a search function
A big list of homoglyphs and some code to detect them
At a glance
- What is it?
- The codebox/homoglyph project compiles Unicode confusables into a list of characters that look alike, and ships a homoglyph aware search in JavaScript and Java so that a banned word is still found when its letters have been swapped for lookalike codepoints. It is a data plus a small function, and its two releases date from 2020 and earlier.
- Who is it for?
- Adopt codebox/homoglyph if you are screening user supplied text for banned words, brand name impersonation or phishing content and you need something small and dependency free that handles the Unicode case, since the JavaScript function is self contained and the Java class handles supplementary plane characters.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 55 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem: a banned word that no longer matches
Homoglyphs are characters with different meanings that look similar or identical to each other, and the README's opening example is the digit 0 next to the capital letter O. The interesting cases are not those, though. The interesting cases are the ones where a word stops matching a blocklist while still meaning the same thing to a reader.
The README states the scenario directly. If a social media website wants to protect its users from offensive language, it may create a blacklist of forbidden words and block any content containing them. Someone wishing to use a blacklisted word could replace one of its letters with a homoglyph, and the word would no longer match the blacklist while its meaning stayed apparent to anyone who saw it.
That is a two character attack against a naive filter, and it works because the modern internet runs on Unicode, which makes it possible to mix letters from many different languages in one place and therefore massively increases the number of homoglyphs available. Homoglyphs within a single alphabet tend to be rare for obvious reasons.
The size of the problem is visible in one line of the README, which lists characters that all render as a capital A. The Greek capital alpha, the Cyrillic capital A, the Cherokee letter, the mathematical bold script capital A, the fullwidth A, and a long tail of mathematical alphanumeric symbols, all with their own unique codepoint values and all looking more or less like the same letter.
This is a defensive tool. The name, the topic list and the home page of homoglyph detection all point at the same use case, and the audience is anyone running a filter, a moderation queue or a brand protection system.
The data: a confusables list plus a sorted text file
The core of the project is data, and the README explains its provenance carefully.
The list of homoglyphs is based on the one that appears on the Unicode Consortium website, at the confusables.txt file. The README is honest that this list, although long, was incomplete, so the author added further pairs found thanks to homoglyphs.net, which the README notes is unfortunately no longer online.
That detail matters. The list is the Unicode data plus a manual supplement, and the manual supplement comes from a source that has since disappeared. Any project adopting this list should treat the supplement as frozen and unverifiable.
The data is published in several forms, and the distinction between them is the useful part. There is a sorted text file with one group of homoglyphs on each line, in raw_data/chars.txt. There is a similar file containing the Unicode codepoint hexadecimal values for each character, in raw_data/char_codes.txt. Those two are the raw inputs, suitable for generating your own representation.
Then there are the search functions. The JavaScript file in javascript/src/homoglyph.js is a JavaScript file containing a homoglyph aware search function, and the README stresses that the file is self-contained with no external dependencies, and contains a single function which accepts a string of text to be searched and a list of target words which must be detected. The Java equivalent is a Java class file containing a homoglyph aware search method.
The README also points at a test page that shows all the character substitutions the implementation can detect, which is a good sign about how the substitution logic is verified.
The Unicode trap that the length property sets
The most interesting engineering in the project is the handling of the Unicode surrogate pair problem, and the README explains it for both languages.
For JavaScript, the README cites Mathias Bynens on JavaScript having a Unicode problem. String processing code that works fine on ordinary English characters behaves unexpectedly when more exotic ones are used. The demonstration is about length:
>'FOUR'.length 4 >'𐊇𐊒𝐔𝐑'.length 8
The plain word has a length of 4 as expected, but the same four letters rendered with high value homoglyphs report a length of 8. This happens for any character with a codepoint value higher than U+FFFF, because JavaScript strings are sequences of UTF-16 code units and those characters are encoded as surrogate pairs.
That breaks naive homoglyph detection in a specific way: a detector that compares string lengths, or that slices a string by index, sees a different number of characters than the text actually contains, so the substitution is either missed or produces mismatched output.
The fix the project applies is the ECMAScript 6 for...of construct, which correctly extracts individual characters from a piece of text and therefore allows a search to be performed on characters rather than on code units.
Java has the same problem for the same historical reason, and the README says so directly. The language was designed when Unicode only used 16 bits to encode each character, so the char data type was specified as 16 bits as well. The standard has since grown and more than 16 bits are needed to represent everything, which means we cannot rely on the length method returning the correct number of characters. The Java class handles high value Unicode characters by using the int datatype to represent codepoint values.
Using it from JavaScript and from Java
Both languages are supported and both are documented with a short example.
The JavaScript package is published on npm as homoglyph-search and is installed with a single command:
npm install homoglyph-searchThe usage is the module's search function called with the text to search and the list of banned words:
var homoglyphSearch = require('homoglyph-search');
var bannedWords = ['credit'];
var textToSearch = 'Get free ϲrEd1ᴛ';
var results = homoglyphSearch.search(textToSearch, bannedWords);The example text is the interesting part. It is a mixed-script spelling of credit, with a Greek lunate sigma, a Greek or similar character, small capitals and a small capital T, so a plain substring search for credit would not find it.
The Java route is through Maven Central, with a dependency block:
<dependency>
<groupId>net.codebox</groupId>
<artifactId>homoglyph</artifactId>
<version>1.2.1</version>
</dependency>And the usage builds a Homoglyph object with the HomoglyphBuilder class and calls its search method with the text and the words:
String textToSearch = "Get free ϲrEd1ᴛ";
String[] bannedWords = new String[]{"credit"};
Homoglyph homoglyph = HomoglyphBuilder.build();
List<SearchResult> results = homoglyph.search(textToSearch, bannedWords);The two APIs are parallel, which makes sense given they solve the same problem in languages with the same underlying codepoint pitfall, and both return a list of search results rather than a bare boolean.
The repository layout shows three implementations plus the data. There is a javascript directory, a node directory, a src directory for the Java code, a generator directory that presumably produces the derived data files, and a raw_data directory holding the source lists, along with a build.gradle for the Java build.
Where homoglyph detection is the wrong tool
There are three boundaries, and the first is the important one.
This detects character substitution. It does not detect a homoglyph attack. A homoglyph attack is a person registering a domain with a Cyrillic character in place of a Latin one, or creating an account named with a lookalike of a brand, and the defence there is a different machine entirely: a policy of what to allow, a reporting and takedown process, and a way to show a user the real name with the confusable characters made visible. A library that finds a banned word spelled with lookalike characters inside a body of text is solving a different problem, and deploying it as if it solved the domain one is a category error.
The second is the data age. The only tagged release listed is 1.2.0, described as updated to use v13.0.0 of the unicode.org confusables list and dated 2020-01-26. The README's own warning is that the confusables list was incomplete and was supplemented by hand, and that supplement came from a site that no longer exists. A confusables list that has not been regenerated in six years will not contain the lookalikes introduced since, and a homoglyph set is exactly the kind of data where new characters appear every year as scripts are designed and emoji are added. The last push was on 2026-08-29, so the repository is being touched, but a touch is not a data refresh.
The third is the operational cost of the matching itself. Every homoglyph group in the list is a set of characters that look alike, so a detector that checks a target word against every character in every group is doing a combinatorial amount of work per input. On a large body of user text, or on a high traffic endpoint, that cost is real, and it is the kind of thing that pushes a team towards a cheaper heuristic that misses the case the library exists to catch. The README does not discuss performance, so you should measure it against your own input sizes rather than assume.
The alternative approach is to normalise before matching, using a Unicode normalisation form such as NFKC or the confusable skeleton mapping, so that lookalike characters are folded to their canonical form and the comparison becomes a plain string comparison. The difference in approach is that this library enumerates the substitutions and searches for each one, while normalisation folds the input once and searches once. Normalisation is cheaper and handles the cases the data covers, and it still depends on the quality and currency of the mapping table you use, so the practical recommendation is to treat this library as a reference implementation and a data source rather than as the runtime dependency.
Editorial conclusion
Adopt codebox/homoglyph if you are screening user supplied text for banned words, brand name impersonation or phishing content and you need something small and dependency free that handles the Unicode case, since the JavaScript function is self contained and the Java class handles supplementary plane characters. Do not adopt it as a complete anti-abuse system, since it detects character substitution and nothing else, and do not expect its confusables data to be current, because the list was compiled against the Unicode Consortium confusables file and the only tagged release is 1.2.0 from 2020-01-26, with the last push on 2026-08-29. Verify first that the confusables list you ship is regenerated from a recent Unicode confusables.txt, that your language can represent supplementary plane codepoints, and that your product policy distinguishes a lookalike substitution from a genuinely different word before you block on a match.
Frequently asked questions
What is codebox/homoglyph and what does it do?
It is a list of homoglyphs, characters with different meanings that look similar or identical to each other, plus code to detect them. The data is based on the Unicode Consortium confusables list with extra pairs added by hand, and it ships a homoglyph aware search function in JavaScript and a Java class file.
How do I use the homoglyph search in JavaScript?
Install the package with npm install homoglyph-search, then require it and call the search function with the text to search and the list of target words, as in the README example that searches for credit in a string mixing Greek and small capital lookalike characters.
How do I use the homoglyph search in Java?
Add the dependency from Maven Central with groupId net.codebox, artifactId homoglyph and version 1.2.1, then build a Homoglyph object with HomoglyphBuilder.build() and call its search method with the text and the banned words, which returns a list of SearchResult.
Why does the homoglyph code use for...of and int codepoints?
Because characters above U+FFFF are encoded as surrogate pairs, so a plain JavaScript string length reports 8 for a four character word written in high value homoglyphs, and Java's char type is 16 bits for the same historical reason. The JavaScript function uses the ECMAScript 6 for...of construct to extract individual characters, and the Java class uses int to represent codepoint values.
How current is the homoglyph confusables data?
The only tagged release listed is 1.2.0, described as updated to use v13.0.0 of the unicode.org confusables list and dated 2020-01-26. The README also notes that the upstream list was incomplete and that extra pairs came from homoglyphs.net, which is no longer online, and the last push to the repository was on 2026-08-29.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/codebox-homoglyph)Was this useful?