fix: add Unicode normalization and homoglyph detection to tool name validation
Closed
MA
3mo ago+170+170+012345678901234567890123456789-0-0-0123456789
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
- Attacker registers tool
verify_սser(ArmenianսU+057D instead of Latins) - Tool appears as
verify_userin UI, logs, and agent context - User or orchestrator believes they are calling the legitimate
verify_usertool - Attacker's malicious
verify_սserexecutes instead - 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():
- NFKC normalization check — if
unicodedata.normalize('NFKC', name) != name, the name contains confusable or fullwidth characters and is rejected - 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_CHARSconstant (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 overridesTestUnicodeNormalizationBypass— 2 tests for decomposed and NFKC normalization formsTestUnicodeBoundaryConditions— 1 test for zero-width charactersTestValidAsciiStillWorks— 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