Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
confusable-vision — 793 confusable pairs missing from Unicode TR39, world-first cross-script dataset, font-aware SSIM scoring across 230 fonts and 22,000+ characters | Kitploit
Tools/GitHubGitHub/paultendo/confusable-vision
OSINT (Open Source Intelligence)ReconnaissanceWeb SecurityThreat IntelligenceSupply Chain SecurityPapers & ResearchLearning & EducationCurated Resources
GitHubpaultendo/confusable-vision

confusable-vision

793 confusable pairs missing from Unicode TR39, world-first cross-script dataset, font-aware SSIM scoring across 230 fonts and 22,000+ characters

View Repository
11215 days agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

confusable-vision

Empirical glyph similarity scoring using vector-outline raycasting. Renders Unicode confusable character pairs across 245 system fonts, measures structural similarity from font outlines directly (no rasterization), and produces scored JSON artifacts with per-font continuous distance scores.

Key results from 52.6 million single-char and 190 million multi-char comparisons across 22,581 characters and 12 writing systems:

  • 249,976 unique single-char confusable pairs across 245 fonts, 12 scripts, 66 cross-script pairs. 764,395 total font-level discoveries.
  • 2,524,275 unique multi-char (bigram) confusable pairs including rn/m across 95 fonts (33 below distance 0.40) and oy/Cyrillic uk across 16 fonts.
  • Per-font continuous distance scores, not binary lists. Each pair has a measured ray distance per font, giving font-aware confidence for downstream security tooling.
  • 305% more discoveries than SDF, 29% faster. The enriched five-layer ray signature is a strict superset of SDF findings; SDF-exclusive pairs did not replicate under manual review.

The output feeds directly into namespace-guard for runtime confusable detection in package names, domain names, and identifiers.

How it works

RaySpace casts parallel rays through font outlines at 36 angles and captures five layers of information per glyph: crossing counts, crossing positions, crossing angles, ping distances (stroke width at each crossing), and ping max (counter width between crossings). This produces a compact signature per character per font. Two signatures are compared with a weighted L1 distance across all five layers.

A three-stage filter cascade makes exhaustive comparison tractable:

  1. Advance width filter (15% tolerance) eliminates pairs with different character widths. Removes 63% of candidates.
  2. Ray comparison (threshold 2.0, tightened to 1.0 for large script pairs). Removes another 33%.
  3. Only 3.3% of candidates survive to become discoveries.

The signature bank (294,646+ entries across 245 fonts; more with --include-uppercase) is precomputed once. Discovery then runs as single-threaded arithmetic on the bank, completing 52.6 million pair comparisons in 31 minutes with no worker threads or GPU.

Quick start

npm install

# 1. Build the ray signature bank (prerequisite, ~24 min)
npx tsx scripts/build-signature-bank.ts

# 1b. Include uppercase Latin A-Z (optional)
#     By default the bank only includes IDNA PVALID codepoints (lowercase,
#     digits, symbols). Use --include-uppercase to add uppercase A-Z, useful
#     for font identification and trademark visual comparison where uppercase
#     glyph shapes matter. The builder is resumable, so this only computes
#     the additional codepoints.
npx tsx scripts/build-signature-bank.ts --include-uppercase

# 1c. Include arbitrary codepoint ranges (optional)
npx tsx scripts/build-signature-bank.ts --extra-range=0041-005A

# 2. Single-char discovery (22,581 chars, 12 scripts, ~36 min)
npx tsx scripts/discover-singlechar-sdf.ts --scorer=ray

# 3. Multi-char (bigram) discovery (676 bigrams, ~63 min)
npx tsx scripts/discover-multichar-sdf.ts --scorer=ray

# 4. Score known TR39 multi-char confusables (~5 min)
npx tsx scripts/score-multichar-sdf.ts --scorer=ray
Legacy SSIM pipeline

The original SSIM-based pipeline scored 26.5 million comparisons across 230 fonts. It remains functional but is superseded by RaySpace for all discovery and scoring tasks.

# TR39 confusable pair scoring
npx tsx scripts/build-index.ts          # Render index (~160s, 11,370 PNGs)
npx tsx scripts/score-all-pairs.ts      # Score all pairs (~65s, 235K comparisons)

# Novel confusable discovery
npx tsx scripts/build-candidates.ts          # Candidate set (~23K chars)
npx tsx scripts/build-index.ts --candidates  # Render candidates (~40min, 89K PNGs)
npx tsx scripts/score-candidates.ts          # Score against Latin targets (~15min, 2.9M comparisons)

# Extract high-scoring discoveries from both pipelines
npx tsx scripts/extract-discoveries.ts

What it found

Top confusable pairs (single-char, mean distance < 0.10)

SourceTargetScriptsMeanFontsZeros
w U+0077ԝ U+051DLatin-Cyrillic0.0001919
j U+006Aϳ U+03F3Latin-Greek0.0132118
i U+0069і U+0456Latin-Cyrillic0.0186250
s U+0073ѕ U+0455Latin-Cyrillic0.0186246
c U+0063с U+0441Latin-Cyrillic0.0196145
o U+006Fо U+043ELatin-Cyrillic0.0206144
j U+006Aј U+0458Latin-Cyrillic0.0216048
x U+0078х U+0445Latin-Cyrillic0.0235950
p U+0070р U+0440Latin-Cyrillic0.0246146
e U+0065е U+0435Latin-Cyrillic0.0326144
a U+0061а U+0430Latin-Cyrillic0.0426145

"Zeros" = fonts where the outlines produce bit-identical ray signatures (distance 0.000). Latin w/Cyrillic ԝ is identical in all 19 fonts that contain both glyphs.

Cross-script breakthroughs (single-char)

SourceTargetScriptsMeanFonts
ο U+03BFჿ U+10FFGreek-Georgian0.0572
ヘ U+30D8へ U+3078Katakana-Hiragana0.12211
丶 U+4E36ヽ U+30FDHan-Katakana0.1259
二 U+4E8Cニ U+30CBHan-Katakana0.24911
口 U+53E3ロ U+30EDHan-Katakana0.26811

Georgian Coda (U+10FF) forms a four-way confusable ring with Latin o, Cyrillic o, and Greek omicron, all below distance 0.08.

Multi-char headline results

BigramTargetMeanFontsNotes
ll॥ U+0965 (Devanagari double danda)0.1768Cross-script
oyѹ U+0479 (Cyrillic uk)0.32216Novel cross-script bigram confusable
rnm U+006D0.5319533 fonts below 0.40
blы U+044B (Cyrillic yeru)0.79749Cross-script

The oy/Cyrillic uk discovery is the standout novel finding: the Latin bigram "oy" is visually identical to the Cyrillic digraph letter uk (ѹ) at distance 0.000 in Helvetica and 0.0005 in Arial Unicode MS.

Threshold calibration

Mean thresholdSingle-char unique pairsMulti-char unique pairs
< 0.5013813
< 1.004,1741,631
< 1.5059,700(noise)
< 2.00249,9762,524,275

Three recommended operating tiers:

  • Strict (< 0.50): 138 single-char pairs, near-zero false positives. Suitable for automated blocking (IDN registration, package name validation) where false positives have real cost.
  • Standard (< 1.00): 4,174 single-char pairs, good balance of coverage and precision. Suitable for flagging and manual review in security tooling.
  • Exploratory (< 2.00): Full discovery set. Contains noise at the upper end but useful for research, font auditing, and building training sets.

Font querying

Query which confusable pairs exist for a specific font. Useful for font designers shipping a new typeface, browser vendors evaluating a system font change, or anyone choosing a display font for security-sensitive contexts like IDN domains.

npx tsx scripts/query-font.ts --list-fonts                    # 218 fonts in discovery data
npx tsx scripts/query-font.ts "Arial"                         # All pairs for Arial (SSIM >= 0.7)
npx tsx scripts/query-font.ts "Arial" --threshold 0.8         # High-confidence only
npx tsx scripts/query-font.ts "Arial" --compare "Georgia"     # Diff two fonts by SSIM delta
npx tsx scripts/query-font.ts "Arial" --json                  # JSON for downstream processing

Font name matching is case-insensitive substring, so "arial" matches Arial, Arial Black, and Arial Unicode MS. Compare mode sorts by the biggest SSIM differences first, surfacing exactly which pairs get better or worse when switching fonts.

Download Tool