Skip to content

fix: add Unicode normalization and homoglyph detection to tool name validation#3141

Open
manjunathbhaskar wants to merge 1 commit into
modelcontextprotocol:mainfrom
manjunathbhaskar:fix/unicode-homoglyph-tool-name-validation
Open

fix: add Unicode normalization and homoglyph detection to tool name validation#3141
manjunathbhaskar wants to merge 1 commit into
modelcontextprotocol:mainfrom
manjunathbhaskar:fix/unicode-homoglyph-tool-name-validation

Conversation

@manjunathbhaskar

Copy link
Copy Markdown

Problem

Tool name validation accepts Unicode homoglyphs — characters that look visually identical to ASCII but are encoded differently. This allows tool names that appear legitimate but are actually distinct identifiers, enabling spoofing attacks in agentic workflows.

Attack Scenario

  1. Attacker registers tool verify_սser (Armenian ս U+057D instead of Latin s)
  2. Tool appears as verify_user in UI, logs, and agent context
  3. User or orchestrator believes they are calling the legitimate verify_user tool
  4. Attacker's malicious verify_սser executes instead
  5. Result: permission escalation, credential theft, data exfiltration

Affected Character Classes (pre-fix)

Category Example Unicode
Cyrillic А looks like Latin A U+0410
Cyrillic О looks like Latin O U+041E
Greek Α looks like Latin A U+0391
Fullwidth a looks like ASCII a U+FF41
RTL Override ‮ reverses displayed text U+202E

Solution

Added two complementary checks to validate_tool_name():

  1. NFKC normalization check — if unicodedata.normalize('NFKC', name) != name, the name contains confusable or fullwidth characters and is rejected
  2. Bidirectional formatting character check — explicitly rejects all 12 Unicode bidi control characters (U+200E, U+200F, U+202A–U+202E, U+2066–U+2069, U+061C) that can reverse or reorder displayed text

Both checks run before the existing regex, so malicious names fail fast with a descriptive error message.

Changes

src/mcp/shared/tool_name_validation.py

  • Added import unicodedata
  • Added BIDIRECTIONAL_FORMATTING_CHARS constant (12 Unicode control characters)
  • Added bidi character detection loop in validate_tool_name()
  • Added NFKC normalization check in validate_tool_name()

tests/shared/test_tool_name_validation.py

  • TestUnicodeHomoglyphDetection — 9 tests covering Cyrillic, Greek, Fullwidth, RTL/LTR overrides
  • TestUnicodeNormalizationBypass — 2 tests for decomposed and NFKC normalization forms
  • TestUnicodeBoundaryConditions — 1 test for zero-width characters
  • TestValidAsciiStillWorks — 5 regression tests confirming valid ASCII names are unaffected

Total: 16 new test cases, 0 breaking changes

Verification

pytest tests/shared/test_tool_name_validation.py -v

All existing tests continue to pass. New tests confirm:

  • Homoglyphs are rejected with a descriptive normalization warning
  • Bidi formatting characters are rejected with a directional warning
  • Valid ASCII tool names (verify_user, tool-name, DATA_EXPORT_v2.1) are unaffected

References

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 2 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread tests/shared/test_tool_name_validation.py Outdated
@manjunathbhaskar
manjunathbhaskar marked this pull request as draft July 21, 2026 10:13
@manjunathbhaskar
manjunathbhaskar force-pushed the fix/unicode-homoglyph-tool-name-validation branch from b034a16 to 7bdaa23 Compare July 21, 2026 10:29
Closes a spoofing attack vector where tool names containing visually
identical but distinct Unicode characters (Cyrillic А vs Latin A,
fullwidth a vs ASCII a, Greek Α vs Latin A) or invisible bidirectional
formatting characters (U+202E RTL override, U+200F RTL mark, etc.) could
bypass the existing ASCII-only regex check undetected.

Changes to src/mcp/shared/tool_name_validation.py:
- Add BIDIRECTIONAL_FORMATTING_CHARS set (12 Unicode control chars)
- Reject names containing any bidi formatting char with a descriptive warning
- Reject names whose NFKC-normalized form differs from the original,
  catching fullwidth look-alikes (a→a) before the regex runs

Changes to tests/shared/test_tool_name_validation.py:
- Add TestUnicodeHomoglyphDetection (9 tests): Cyrillic А/О/Е/Р, fullwidth,
  Greek Α, RTL/LTR override characters
- Add TestUnicodeNormalizationBypass (2 tests): NFD decomposed forms,
  NFKC fullwidth normalization
- Add TestUnicodeBoundaryConditions (1 test): zero-width space
- Add TestValidAsciiStillWorks (5 tests): confirm existing valid names
  still pass after new checks
@manjunathbhaskar
manjunathbhaskar force-pushed the fix/unicode-homoglyph-tool-name-validation branch from 9825cfa to ddeb025 Compare July 21, 2026 10:44
@manjunathbhaskar
manjunathbhaskar marked this pull request as ready for review July 21, 2026 16:43

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 2 files

Re-trigger cubic

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