{"id":"CVE-2026-126349","kind":"vulnerability","aliases":["CVE-2026-126349","GHSA-539f-xcgw-2gjg"],"related":[],"title":"Addressable display_uri can show misleading hosts containing bidi and invisible characters","description":"### Impact\n\n`Addressable::IDNA.to_unicode` decodes Punycode labels (labels beginning with `xn--`) that contain characters which change how text is displayed without being visible themselves. These include bidirectional controls such as U+202E RIGHT-TO-LEFT OVERRIDE and U+2066–U+2069, zero-width characters, and other invisible format characters. `Addressable::URI#display_uri` uses `to_unicode`, so it can display a host whose characters appear reordered or which looks identical to a different host. For example, the host of `http://xn--abcmoc-dm0c.com/` is displayed as `abc`, U+202E, `moc.com`, and the override makes everything after `abc` render right to left.\n\nParsing, `host`, `normalized_host` and any connection made from the URI are not affected. Only the displayed form is. Applications that show `display_uri` to users (link previews, chat and email clients, admin interfaces) can be used to make a malicious domain look like a trusted one.\n\n- In the pure-Ruby IDNA implementation, all such characters are decoded, including those that IDNA's nameprep profile prohibits.\n- In the native IDNA implementation, used when libidn and the `idn-ruby` gem are installed, libidn rejects most of them, but not characters added to Unicode after version 3.2, such as U+061C and U+2066–U+2069.\n\n### Affected Versions\n\nThe pure-Ruby IDNA implementation is affected in Addressable >= 2.0.0. The native IDNA implementation is affected in Addressable >= 2.5.2, when `to_unicode` began accepting characters unassigned in Unicode 3.2. It is fixed in 2.9.1 for both implementations, where such labels are returned unchanged.\n\n### Workarounds\n\n- Install libidn and the `idn-ruby` gem, so that Addressable uses the native IDNA implementation. This reduces the affected characters to those added since Unicode 3.2.\n- Check displayed hosts for bidirectional and invisible characters (e.g., `/[\\p{Cc}\\p{Cf}\\p{Default_Ignorable_Code_Point}]/`) and fall back to `normalized_host` when one is present.\n\n### Credits\n\nReported by @andrewstellman.\n\n### For more information\n\nIf there are any questions or comments about this advisory:\n* [Open an issue](https://github.com/sporkmonger/addressable/issues)","summary":"Addressable's display_uri decodes Punycode hosts containing bidirectional and invisible Unicode characters, so a malicious domain can be shown looking like a trusted one. The parsed host and connections are not affected; only the displayed text is misleading.","severity":"low","cvss":3.1,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"addressable","fixed":["2.9.1"],"affected":">= 2.0.0, < 2.9.1","ecosystem":"rubygems"}],"ecosystems":["rubygems"],"tags":["addressable","cwe-1007","cwe-176","cwe-451","package","rails","ruby"],"not_affected_if":["no-display-uri-output","uses-normalized-host-only"],"how_to_check":"- Check the version of addressable in `Gemfile.lock` (look for `addressable (`) and compare with `2.9.1`.\n- Search application code for `display_uri` and for places where its output is shown to users, such as link previews, chat, email or admin screens.","fix":"- `addressable` `2.9.1` (fixed version; affected range is `>= 2.0.0, < 2.9.1`)","status":"open","published_at":"2026-11-12T22:19:20+00:00","first_seen_at":"2026-11-12T22:40:37+00:00","triaged_at":"2026-11-12T22:48:47+00:00","updated_at":"2026-11-12T22:48:47+00:00","category":"package","confidence":0.85,"triage":{"at":"2026-11-12T22:48:47Z","model":"claude-haiku-5-5","output":{"fix":"- `addressable` `2.9.1` (fixed version; affected range is `>= 2.0.0, < 2.9.1`)","reach":"internet","title":"Addressable: display_uri can show misleading hosts with hidden characters","impact":"low","summary":"Addressable's display_uri decodes Punycode hosts containing bidirectional and invisible Unicode characters, so a malicious domain can be shown looking like a trusted one. The parsed host and connections are not affected; only the displayed text is misleading.","audience":"developers","category":"package","nicknames":[],"who_cares":["ruby","rails","addressable"],"confidence":0.85,"fix_status":"available","needs_auth":"no","worst_case":"users are shown a spoofed domain that looks trusted","analyst_note":"Product name is listed in the input, so product_name is empty.","how_to_check":"- Check the version of addressable in `Gemfile.lock` (look for `addressable (`) and compare with `2.9.1`.\n- Search application code for `display_uri` and for places where its output is shown to users, such as link previews, chat, email or admin screens.","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["no-display-uri-output","uses-normalized-host-only"],"who_is_affected":"Applications that use Addressable's display_uri and show its output to people, such as link previews, chat or email clients and admin interfaces, can be used to disguise a malicious domain as a trusted one. Code that only parses URIs or connects to hosts is not affected, and neither is code that never displays display_uri output.","user_interaction":"yes","product_ecosystem":"","needs_special_setup":"no","severity_if_unknown":"low"},"cost_usd":0.000827,"input_tokens":5422,"output_tokens":570,"severity_before":"low"},"analyst_status":null,"analyst_note":null,"search":"'+061':277C '+202':105C,163C '+2066':114C,281C '+2069':116C,283C '-1007':27B '-126349':15A,23A '-176':29B '-2026':14A,22A '-451':31B '/sporkmonger/addressable/issues)':408C '2.0.0':296C '2.5.2':305C '2.9.1':320C '2gjg':20A '3.2':273C,315C,357C '539f':18A 'abc':161C,172C 'abcmoc-dm0c.com':157C 'accept':310C 'add':268C,354C 'address':1A,25B,35B,75C,126C,295C,304C,341C 'addressable':24A 'admin':209C 'advisori':402C 'affect':67B,190C,284C,293C,302C,350C 'andrewstellman':389C 'appear':141C 'applic':196C 'back':378C 'began':309C 'begin':82C 'bidi':9A 'bidirect':43B,100C,362C 'c':278C 'cc':368C 'cf':370C 'chang':89C 'charact':12A,47B,87C,120C,125C,140C,233C,267C,311C,351C,365C 'chat':205C 'check':358C 'client':208C 'code':374C 'comment':399C 'connect':64B,183C 'contain':8A,42B,86C 'control':101C 'credit':386C 'cve':13A,21A 'cwe':26B,28B,30B 'decod':39B,78C,235C 'default':372C 'differ':149C 'display':2A,37B,70B,93C,128C,136C,159C,193C,199C,359C 'domain':51B,218C 'e':106C,164C 'e.g':366C 'email':207C 'everyth':170C 'exampl':152C 'fall':377C 'fix':318C 'form':194C 'format':124C 'gem':257C,338C 'ghsa':17A 'ghsa-539f-xcgw-2gjg':16A 'github.com':407C 'github.com/sporkmonger/addressable/issues)':406C 'host':7A,41B,62B,138C,150C,154C,178C,180C,360C,381C 'ident':146C 'idn':255C,336C 'idn-rubi':254C,335C 'idna':229C,239C,247C,290C,299C,345C 'idna.to':76C 'ignor':373C 'impact':74C 'implement':230C,248C,291C,300C,323C,346C 'includ':99C,236C 'inform':392C 'instal':259C,331C 'interfac':210C 'invis':11A,45B,123C,364C 'issu':405C 'label':80C,81C,326C 'left':110C,176C 'libidn':251C,260C,332C 'like':56B,220C 'link':203C 'look':55B,145C,219C 'made':184C 'make':169C,215C 'malici':50B,217C 'mislead':6A,73B 'moc.com':165C 'nameprep':241C 'nativ':246C,298C,344C 'normal':179C,380C 'one':59B,223C,383C 'open':403C 'overrid':111C,168C 'p':367C,369C,371C 'packag':32B 'pars':61B,177C 'point':375C 'present':385C 'preview':204C 'profil':242C 'prohibit':243C 'punycod':40B,79C 'pure':227C,288C 'pure-rubi':226C,287C 'question':397C 'rail':33B 'reduc':348C 'reject':261C 'render':173C 'reorder':142C 'report':387C 'return':328C 'right':108C,174C 'right-to-left':107C 'rubi':34B,228C,256C,289C,337C 'show':5A,198C 'shown':54B 'sinc':355C 'text':71B,91C 'trust':58B,222C 'u':104C,113C,115C,162C,276C,280C,282C 'unassign':312C 'unchang':329C 'unicod':46B,77C,132C,270C,308C,314C,356C 'uri':3A,38B,127C,129C,187C,200C 'use':130C,213C,249C,342C 'user':202C 'version':272C,285C 'visibl':96C 'whose':139C 'width':119C 'without':94C 'workaround':330C 'xcgw':19A 'xn':84C,156C 'zero':118C 'zero-width':117C","nicknames":[],"mitigations":[],"who_affected":"Applications that use Addressable's display_uri and show its output to people, such as link previews, chat or email clients and admin interfaces, can be used to disguise a malicious domain as a trusted one. Code that only parses URIs or connects to hosts is not affected, and neither is code that never displays display_uri output.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":["addressable"],"ptokens":["addressable"],"labels":["addressable","cwe1007","cwe176","cwe451","low","package","rails","ruby","rubygems"],"campaign_type":null,"search_a":"'-126349':15A,23A '-2026':14A,22A '2gjg':20A '539f':18A 'address':1A 'addressable':24A 'bidi':9A 'charact':12A 'contain':8A 'cve':13A,21A 'display':2A 'ghsa':17A 'ghsa-539f-xcgw-2gjg':16A 'host':7A 'invis':11A 'mislead':6A 'show':5A 'uri':3A 'xcgw':19A","search_b":"'-1007':27B '-176':29B '-451':31B 'address':25B,35B 'affect':67B 'bidirect':43B 'charact':47B 'connect':64B 'contain':42B 'cwe':26B,28B,30B 'decod':39B 'display':37B,70B 'domain':51B 'host':41B,62B 'invis':45B 'like':56B 'look':55B 'malici':50B 'mislead':73B 'one':59B 'packag':32B 'pars':61B 'punycod':40B 'rail':33B 'rubi':34B 'shown':54B 'text':71B 'trust':58B 'unicod':46B 'uri':38B","search_c":"'+061':277C '+202':105C,163C '+2066':114C,281C '+2069':116C,283C '/sporkmonger/addressable/issues)':408C '2.0.0':296C '2.5.2':305C '2.9.1':320C '3.2':273C,315C,357C 'abc':161C,172C 'abcmoc-dm0c.com':157C 'accept':310C 'add':268C,354C 'address':75C,126C,295C,304C,341C 'admin':209C 'advisori':402C 'affect':190C,284C,293C,302C,350C 'andrewstellman':389C 'appear':141C 'applic':196C 'back':378C 'began':309C 'begin':82C 'bidirect':100C,362C 'c':278C 'cc':368C 'cf':370C 'chang':89C 'charact':87C,120C,125C,140C,233C,267C,311C,351C,365C 'chat':205C 'check':358C 'client':208C 'code':374C 'comment':399C 'connect':183C 'contain':86C 'control':101C 'credit':386C 'decod':78C,235C 'default':372C 'differ':149C 'display':93C,128C,136C,159C,193C,199C,359C 'domain':218C 'e':106C,164C 'e.g':366C 'email':207C 'everyth':170C 'exampl':152C 'fall':377C 'fix':318C 'form':194C 'format':124C 'gem':257C,338C 'github.com':407C 'github.com/sporkmonger/addressable/issues)':406C 'host':138C,150C,154C,178C,180C,360C,381C 'ident':146C 'idn':255C,336C 'idn-rubi':254C,335C 'idna':229C,239C,247C,290C,299C,345C 'idna.to':76C 'ignor':373C 'impact':74C 'implement':230C,248C,291C,300C,323C,346C 'includ':99C,236C 'inform':392C 'instal':259C,331C 'interfac':210C 'invis':123C,364C 'issu':405C 'label':80C,81C,326C 'left':110C,176C 'libidn':251C,260C,332C 'like':220C 'link':203C 'look':145C,219C 'made':184C 'make':169C,215C 'malici':217C 'moc.com':165C 'nameprep':241C 'nativ':246C,298C,344C 'normal':179C,380C 'one':223C,383C 'open':403C 'overrid':111C,168C 'p':367C,369C,371C 'pars':177C 'point':375C 'present':385C 'preview':204C 'profil':242C 'prohibit':243C 'punycod':79C 'pure':227C,288C 'pure-rubi':226C,287C 'question':397C 'reduc':348C 'reject':261C 'render':173C 'reorder':142C 'report':387C 'return':328C 'right':108C,174C 'right-to-left':107C 'rubi':228C,256C,289C,337C 'show':198C 'sinc':355C 'text':91C 'trust':222C 'u':104C,113C,115C,162C,276C,280C,282C 'unassign':312C 'unchang':329C 'unicod':77C,132C,270C,308C,314C,356C 'uri':127C,129C,187C,200C 'use':130C,213C,249C,342C 'user':202C 'version':272C,285C 'visibl':96C 'whose':139C 'width':119C 'without':94C 'workaround':330C 'xn':84C,156C 'zero':118C 'zero-width':117C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-10-30T08:14:19+00:00","kev":null,"cvss_vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:L/A:N","cvss_by":"GitHub","poc_count":0,"sources":[{"source":"nvd","external_id":"CVE-2026-126349","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-126349","severity":null,"published_at":"2026-11-12T22:19:20+00:00","modified_at":"2026-11-12T22:19:20+00:00","first_seen_at":"2026-11-12T22:40:37+00:00","fetched_at":"2026-11-12T22:40:37+00:00","note":null},{"source":"ghsa","external_id":"GHSA-539f-xcgw-2gjg","url":"https://github.com/advisories/GHSA-539f-xcgw-2gjg","severity":"low","published_at":"2026-11-12T22:44:15+00:00","modified_at":"2026-11-12T22:44:17+00:00","first_seen_at":"2026-11-12T22:47:10+00:00","fetched_at":"2026-11-12T22:49:35+00:00","note":null}],"documents":[{"id":139807,"url":"https://github.com/sporkmonger/addressable/commit/60455d32bb59fda2585a0e1865a9fcb21e8e55b1","title":"Patch: github.com","kind":"other","source":"nvd","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":139737,"url":"https://github.com/sporkmonger/addressable/releases/tag/addressable-2.9.1","title":"Release: github.com","kind":"release","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Release notes: github.com"},{"id":139809,"url":"https://github.com/sporkmonger/addressable/security/advisories/GHSA-539f-xcgw-2gjg","title":"Vendor advisory: github.com","kind":"vendor","source":"nvd","publisher":"vendor","text":null,"published_at":"2026-10-30T08:14:19+00:00","relation":"advisory","confidence":null,"note":"Vendor advisory: github.com"},{"id":140039,"url":"https://api.github.com/repos/sporkmonger/addressable/security-advisories/GHSA-539f-xcgw-2gjg","title":"Maintainer's advisory: api.github.com","kind":"vendor","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: api.github.com"}],"disclosures":[],"exploit_sources":[],"notice":"Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai"}