{"id":"CVE-2026-126348","kind":"vulnerability","aliases":["CVE-2026-126348","GHSA-9crm-g4mf-wc5j"],"related":[],"title":"Addressable display_uri can show misleading hosts with invalid Punycode A-labels","description":"### Impact\n\n`Addressable::IDNA.to_unicode`, in the pure-Ruby IDNA implementation, decodes Punycode labels (labels beginning with `xn--`) that are not valid A-labels. Those labels are returned in decoded form, when they should be returned unchanged. That includes:\n\n- labels that decode to only ASCII characters, e.g. `xn--google-` decodes to `google`;\n- labels that decode to text that doesn't convert back to the same label (RFC 3490 §4.2), e.g. text that isn't in normalized form.\n\n`Addressable::URI#display_uri` uses `to_unicode`, so for `https://xn--google-.example.org/` it displays the host `google.example.org`, while `#host`, `#normalized_host` and any connection made from the URI use `xn--google-.example.org`. An attacker who controls a domain can therefore have a URI displayed as a host they don't control. Applications that compare the result of `to_unicode` against a list of trusted names can likewise treat two different hosts as the same.\n\nThe native IDNA implementation, used when libidn and the `idn-ruby` gem are installed, is not affected. `to_ascii` and `normalized_host` are not affected.\n\n### Affected Versions\n\nThis vulnerability affects Addressable >= 2.0.0, the first version with the pure-Ruby IDNA implementation, when that implementation is in use. It is fixed in 2.9.1, where such labels are returned unchanged, as with libidn.\n\n### Workarounds\n\n- Install libidn and the `idn-ruby` gem, so that Addressable uses the native IDNA implementation.\n- Don't make security decisions on `display_uri` or `to_unicode` output. Compare hosts using `normalized_host`.\n\n### Credits\n\nReported by @tonghuaroot.\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":"The Ruby Addressable library decodes invalid Punycode host labels when building display text, so a URL can show a different hostname than the one it actually connects to. An attacker who controls a domain can make a link look like a trusted host.","severity":"medium","cvss":4.3,"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-20","package","ruby","rubygems"],"not_affected_if":["native-idn","normalized-host-only"],"how_to_check":"- Check the installed version with `bundle exec gem list addressable` or look for `addressable` in Gemfile.lock.\n- Check whether the native IDNA is in use: `gem list idn-ruby` (if present with libidn, the pure-Ruby path is not used).\n- Look for code that uses `display_uri` or `to_unicode` output for trust or host comparison.","fix":"- Addressable: upgrade to `2.9.1`.","status":"open","published_at":"2026-11-12T22:19:19+00:00","first_seen_at":"2026-11-12T22:40:37+00:00","triaged_at":"2026-11-12T22:48:46+00:00","updated_at":"2026-11-12T22:48:46+00:00","category":"package","confidence":0.8,"triage":{"at":"2026-11-12T22:48:46Z","model":"claude-haiku-5-5","output":{"fix":"- Addressable: upgrade to `2.9.1`.","reach":"unknown","title":"Addressable: display_uri can show a misleading host for bad Punycode","impact":"low","summary":"The Ruby Addressable library decodes invalid Punycode host labels when building display text, so a URL can show a different hostname than the one it actually connects to. An attacker who controls a domain can make a link look like a trusted host.","audience":"developers","category":"package","nicknames":[],"who_cares":["ruby","addressable","rubygems"],"confidence":0.8,"fix_status":"available","needs_auth":"no","worst_case":"users are shown a hostname that differs from the real connection target","analyst_note":"","how_to_check":"- Check the installed version with `bundle exec gem list addressable` or look for `addressable` in Gemfile.lock.\n- Check whether the native IDNA is in use: `gem list idn-ruby` (if present with libidn, the pure-Ruby path is not used).\n- Look for code that uses `display_uri` or `to_unicode` output for trust or host comparison.","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["native-idn","normalized-host-only"],"who_is_affected":"Applications that use the pure-Ruby IDNA path of Addressable (2.0.0 up to but not including 2.9.1) and show `display_uri` output to users or compare `to_unicode` results against trusted host lists. Systems that install libidn with the idn-ruby gem use the native implementation and are not affected, and code that only uses `normalized_host` for comparisons is not affected.","user_interaction":"yes","product_ecosystem":"","needs_special_setup":"yes","severity_if_unknown":"unknown"},"cost_usd":0.000826,"input_tokens":5260,"output_tokens":600,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-1007':28B '-126348':16A,24A '-20':30B '-2026':15A,23A '/sporkmonger/addressable/issues)':348C '2.0.0':261C '2.9.1':282C '3490':145C '4.2':146C '9crm':19A 'a-label':11A,99C 'actual':59B 'address':1A,26B,36B,78C,155C,260C,303C 'addressable':25A 'advisori':342C 'affect':246C,254C,255C,259C 'applic':206C 'ascii':122C,248C 'attack':63B,188C 'back':139C 'begin':92C 'build':44B 'charact':123C 'comment':339C 'compar':208C,321C 'connect':60B,178C 'control':65B,190C,205C 'convert':138C 'credit':326C 'cve':14A,22A 'cwe':27B,29B 'decis':313C 'decod':38B,88C,107C,119C,127C,132C 'differ':53B,224C 'display':2A,45B,157C,168C,198C,315C 'doesn':136C 'domain':67B,192C 'e.g':124C,147C 'example.org':166C,186C 'first':263C 'fix':280C 'form':108C,154C 'g4mf':20A 'gem':241C,300C 'ghsa':18A 'ghsa-9crm-g4mf-wc5j':17A 'github.com':347C 'github.com/sporkmonger/addressable/issues)':346C 'googl':126C,129C,165C,185C 'google.example.org':171C 'host':7A,41B,76B,170C,173C,175C,201C,225C,251C,322C,325C 'hostnam':54B 'idn':239C,298C 'idn-rubi':238C,297C 'idna':86C,231C,270C,307C 'idna.to':79C 'impact':77C 'implement':87C,232C,271C,274C,308C 'includ':116C 'inform':332C 'instal':243C,293C 'invalid':9A,39B 'isn':150C 'issu':345C 'label':13A,42B,90C,91C,101C,103C,117C,130C,143C,285C 'libidn':235C,291C,294C 'librari':37B 'like':73B 'likewis':221C 'link':71B 'list':216C 'look':72B 'made':179C 'make':69B,311C 'mislead':6A 'name':219C 'nativ':230C,306C 'normal':153C,174C,250C,324C 'one':57B 'open':343C 'output':320C 'packag':31B 'punycod':10A,40B,89C 'pure':84C,268C 'pure-rubi':83C,267C 'question':337C 'report':327C 'result':210C 'return':105C,113C,287C 'rfc':144C 'rubi':32B,35B,85C,240C,269C,299C 'rubygem':33B 'secur':312C 'show':5A,51B 'text':46B,134C,148C 'therefor':194C 'tonghuaroot':329C 'treat':222C 'trust':75B,218C 'two':223C 'unchang':114C,288C 'unicod':80C,161C,213C,319C 'uri':3A,156C,158C,182C,197C,316C 'url':49B 'use':159C,183C,233C,277C,304C,323C 'valid':98C 'version':256C,264C 'vulner':258C 'wc5j':21A 'workaround':292C 'xn':94C,125C,164C,184C","nicknames":[],"mitigations":[],"who_affected":"Applications that use the pure-Ruby IDNA path of Addressable (2.0.0 up to but not including 2.9.1) and show `display_uri` output to users or compare `to_unicode` results against trusted host lists. Systems that install libidn with the idn-ruby gem use the native implementation and are not affected, and code that only uses `normalized_host` for comparisons is not affected.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":["addressable"],"ptokens":["addressable"],"labels":["addressable","cwe1007","cwe20","medium","package","ruby","rubygems"],"campaign_type":null,"search_a":"'-126348':16A,24A '-2026':15A,23A '9crm':19A 'a-label':11A 'address':1A 'addressable':25A 'cve':14A,22A 'display':2A 'g4mf':20A 'ghsa':18A 'ghsa-9crm-g4mf-wc5j':17A 'host':7A 'invalid':9A 'label':13A 'mislead':6A 'punycod':10A 'show':5A 'uri':3A 'wc5j':21A","search_b":"'-1007':28B '-20':30B 'actual':59B 'address':26B,36B 'attack':63B 'build':44B 'connect':60B 'control':65B 'cwe':27B,29B 'decod':38B 'differ':53B 'display':45B 'domain':67B 'host':41B,76B 'hostnam':54B 'invalid':39B 'label':42B 'librari':37B 'like':73B 'link':71B 'look':72B 'make':69B 'one':57B 'packag':31B 'punycod':40B 'rubi':32B,35B 'rubygem':33B 'show':51B 'text':46B 'trust':75B 'url':49B","search_c":"'/sporkmonger/addressable/issues)':348C '2.0.0':261C '2.9.1':282C '3490':145C '4.2':146C 'a-label':99C 'address':78C,155C,260C,303C 'advisori':342C 'affect':246C,254C,255C,259C 'applic':206C 'ascii':122C,248C 'attack':188C 'back':139C 'begin':92C 'charact':123C 'comment':339C 'compar':208C,321C 'connect':178C 'control':190C,205C 'convert':138C 'credit':326C 'decis':313C 'decod':88C,107C,119C,127C,132C 'differ':224C 'display':157C,168C,198C,315C 'doesn':136C 'domain':192C 'e.g':124C,147C 'example.org':166C,186C 'first':263C 'fix':280C 'form':108C,154C 'gem':241C,300C 'github.com':347C 'github.com/sporkmonger/addressable/issues)':346C 'googl':126C,129C,165C,185C 'google.example.org':171C 'host':170C,173C,175C,201C,225C,251C,322C,325C 'idn':239C,298C 'idn-rubi':238C,297C 'idna':86C,231C,270C,307C 'idna.to':79C 'impact':77C 'implement':87C,232C,271C,274C,308C 'includ':116C 'inform':332C 'instal':243C,293C 'isn':150C 'issu':345C 'label':90C,91C,101C,103C,117C,130C,143C,285C 'libidn':235C,291C,294C 'likewis':221C 'list':216C 'made':179C 'make':311C 'name':219C 'nativ':230C,306C 'normal':153C,174C,250C,324C 'open':343C 'output':320C 'punycod':89C 'pure':84C,268C 'pure-rubi':83C,267C 'question':337C 'report':327C 'result':210C 'return':105C,113C,287C 'rfc':144C 'rubi':85C,240C,269C,299C 'secur':312C 'text':134C,148C 'therefor':194C 'tonghuaroot':329C 'treat':222C 'trust':218C 'two':223C 'unchang':114C,288C 'unicod':80C,161C,213C,319C 'uri':156C,158C,182C,197C,316C 'use':159C,183C,233C,277C,304C,323C 'valid':98C 'version':256C,264C 'vulner':258C 'workaround':292C 'xn':94C,125C,164C,184C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-10-30T08:14:30+00:00","kev":null,"cvss_vector":"CVSS:3.1/AV:N/AC:L/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-126348","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-126348","severity":null,"published_at":"2026-11-12T22:19:19+00:00","modified_at":"2026-11-12T22:19:19+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-9crm-g4mf-wc5j","url":"https://github.com/advisories/GHSA-9crm-g4mf-wc5j","severity":"medium","published_at":"2026-11-12T22:44:57+00:00","modified_at":"2026-11-12T22:44:58+00:00","first_seen_at":"2026-11-12T22:47:10+00:00","fetched_at":"2026-11-12T22:57:33+00:00","note":null}],"documents":[{"id":139804,"url":"https://github.com/sporkmonger/addressable/commit/b8a59cc0e03f8704f1d7c8122fc8f7ef8548362d","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":139806,"url":"https://github.com/sporkmonger/addressable/security/advisories/GHSA-9crm-g4mf-wc5j","title":"Vendor advisory: github.com","kind":"vendor","source":"nvd","publisher":"vendor","text":null,"published_at":"2026-10-30T08:14:30+00:00","relation":"advisory","confidence":null,"note":"Vendor advisory: github.com"},{"id":140035,"url":"https://api.github.com/repos/sporkmonger/addressable/security-advisories/GHSA-9crm-g4mf-wc5j","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"}