UnicodeSecurity

Pinned Unicode identifier security for Elixir: confusable comparison keys, script and restriction checks, and hostname policy. Unicode 18.0.0 data is final. Runtime calls are pure Elixir, offline, and have no dependencies.

CI Hex version Hex downloads HexDocs Elixir 1.14+ License: MIT

A skeleton is a comparison key. It is not a canonical identifier, a display replacement, or an authorization decision. Equal skeletons do not prove ownership or intent.

Installation

Add unicode_security to your dependencies:

def deps do
[
{:unicode_security, "~> 0.1"}
]
end

Comparison keys

UnicodeSecurity.skeleton("paypal")
#=> "paypal"
# The two visually similar letters are Cyrillic U+0430.
UnicodeSecurity.skeleton("p\u0430yp\u0430l")
#=> "paypal"

skeleton/1 implements bidiSkeleton(LTR, input) from UTS #39 revision 34. Inputs are UTF-8 binaries of at most 4,096 bytes. See Hexdocs for the full key algorithm.

Policy checks

check/2 requires type: :username, :tenant_slug, :organization_name, or :domain. It returns the original input plus a verdict and reasons. It does not trim, rewrite, or reserve the name.

UnicodeSecurity.check("alice-smith", type: :username).verdict
#=> :safe
UnicodeSecurity.check("pay\u200Dpal", type: :username).verdict
#=> :dangerous

Hostnames

Pass type: :domain explicitly. Generic skeleton and comparison functions never guess a domain from a dot.

result = UnicodeSecurity.check("BÜCHER.例え.", type: :domain)
result.domain.ascii
#=> "xn--bcher-kva.xn--r8jz45g."

This is hostname analysis. It does not query DNS, check public suffixes, or parse browser URLs.

Scope

The package does not:

Applications keep the original value and decide uniqueness, ownership, and storage.

License

MIT. See LICENSE. Unicode data attribution is recorded in THIRD_PARTY_NOTICES.md.