Skip to content

Optional homoglyph / confusable-domain detection (opt-in) - #68

Merged
mmucklo merged 2 commits into
masterfrom
feature/confusable-domain-detection
Aug 20, 2026
Merged

Optional homoglyph / confusable-domain detection (opt-in)#68
mmucklo merged 2 commits into
masterfrom
feature/confusable-domain-detection

Conversation

@mmucklo

@mmucklo mmucklo commented Aug 20, 2026

Copy link
Copy Markdown
Owner

Adds opt-in homoglyph / confusable-domain detection for the 3.8.0 minor.

What

ParseOptions::withDetectConfusableDomain(true) flags mixed-script "look-alike" domains — e.g. аpple.com where the а is Cyrillic (U+0430), the classic IDN homograph attack — via the intl Spoofchecker.

  • Security policy, not RFC validity. The address stays valid; the result carries a new field ParsedEmailAddress::$domainIsSuspicious (and domain_is_suspicious in the array API).
  • Off by default, fully additive.
  • No false positives on legitimate international domains: single-script domains like почта.рф, münchen.de, and CJK are not flagged — only mixed-script confusables are.
  • Spoofchecker is created lazily and reused across a batch; guarded by class_exists so the build degrades gracefully without intl.

Out of scope

Confusable-against-a-target-list matching ("looks like paypal.com") — that needs a caller-supplied brand/skeleton set, so it's not part of this self-contained check.

Verification

108 tests (new testConfusableDomainDetection covers homograph-flagged-but-valid, opt-in gating, and the legit-domain non-false-positives); PHPStan level 8 / Psalm / CS Fixer clean. The array-shape tests use the existing opt-in key pattern (like obs_route), so no existing consumer sees a shape change.

withDetectConfusableDomain(true) flags mixed-script "look-alike" domains
(e.g. "аpple.com" with a Cyrillic а) via the intl Spoofchecker. This is a
security-policy signal, not RFC validity: the address stays valid and the
result carries a new ParsedEmailAddress::$domainIsSuspicious field
(domain_is_suspicious in the array API). Off by default; single-script
international domains (почта.рф, münchen.de) are not flagged. The Spoofchecker
is created lazily and reused across a batch, and guarded by class_exists so the
build degrades gracefully without intl.

108 tests; PHPStan level 8 / Psalm / cs clean.
@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.01%. Comparing base (4059cef) to head (41d458c).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##             master      #68      +/-   ##
============================================
+ Coverage     95.59%   96.01%   +0.42%     
- Complexity      428      434       +6     
============================================
  Files             6        6              
  Lines          1066     1078      +12     
============================================
+ Hits           1019     1035      +16     
+ Misses           47       43       -4     
Files with missing lines Coverage Δ
src/Parse.php 94.59% <100.00%> (+0.58%) ⬆️
src/ParseOptions.php 99.03% <100.00%> (+0.01%) ⬆️
src/ParsedEmailAddress.php 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@mmucklo
mmucklo merged commit c769afc into master Aug 20, 2026
14 checks passed
@mmucklo
mmucklo deleted the feature/confusable-domain-detection branch August 20, 2026 05:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant