[GHSA-xq7p-g2vc-g82p] Homograph attack allows Unicode lookalike characters to bypass validation.#7466
Conversation
|
Hi there @junderw! A community member has suggested an improvement to your security advisory. If approved, this change will affect the global advisory listed at github.com/advisories. It will not affect the version listed in your project repository. This change will be reviewed by our Security Curation Team. If you have thoughts or feedback, please share them in a comment here! If this PR has already been closed, you can start a new community contribution for this advisory |
|
Thank you for taking the time to share this information. While we appreciate the effort, we’re not able to assist with these requests. Please reach out directly to the affected repository maintainers with the details so they can verify the correct fixed versions and update the advisory at the source. This guidance also applies to #7485 |
Updates
Comments
CVE-2025-27611 is exploitable through the
decodeUnsafeinner loop, which uses aUint8Array(256)lookup table indexed bycharCodeAt(). When the input contains a Unicode homoglyph whose code point exceeds255, the typed-array access returnsundefined. Becauseundefined !== 255, the sentinel checkif (carry === 255) returnis bypassed. From there,undefined + numberyieldsNaN,NaN >>> 0becomes0, and the invalid character is silently interpreted as the first alphabet symbol. The fix in3.0.11adds an explicitif (charCode > 255) returnguard before the lookup; the same fix was later released in4.0.1and5.0.1.This vulnerable implementation was introduced in
3.0.5as part of a performance rewrite. Every earlier release—the entire1.xline, the entire2.xline, and3.0.0through3.0.4—uses a plain JavaScript object for alphabet lookup:In those versions,
ALPHABET_MAPis keyed by the actual character string rather than by numeric character code. A Unicode homoglyph lookup therefore returnsundefined, and the existing=== undefinedcheck correctly rejects it. There is no out-of-bounds read, no sentinel bypass, and no silent reinterpretation of the invalid character as a valid digit. A homograph PoC against any pre-3.0.5release stops at that validation check and does not reach a vulnerable state.The vulnerability first appears in the
3.0.4 -> 3.0.5rewrite, which replaces the object-based map withBASE_MAP = new Uint8Array(256)and changes the invalid-character sentinel fromundefinedto255. That optimization introduces the vulnerable shape by combiningcharCodeAt()indexing with a fixed-size typed array and an incomplete bounds check.Evidence
1.0.0,1.0.4,1.1.0,2.0.6,3.0.0,3.0.1,3.0.2,3.0.3,3.0.4,3.0.5,3.0.6,3.0.7,3.0.8,3.0.9,3.0.10,3.0.11,4.0.0,4.0.1,5.0.0,5.0.1ALPHABET_MAP,BASE_MAP,new Uint8Array(256), andcharCodeAt()shows the implementation cutover at3.0.4 -> 3.0.53.0.4decode path usesALPHABET_MAP[string[i]]followed byif (value === undefined) return, so no out-of-bounds typed-array access is possible3.0.5decode path usesBASE_MAP[source.charCodeAt(psz)]followed byif (carry === 255) return, which is the vulnerable pattern3.0.11addsif (charCode > 255) returnbefore theBASE_MAPlookup; equivalent fixes appear in4.0.1and5.0.1Conclusion
The correct introduced version is
3.0.5, not any earlier release. Versions prior to3.0.5use a character-keyed object map that correctly rejects Unicode homoglyph input and do not contain the typed-array lookup pattern required for exploitation.