{"id":"GHSA-2p2f-4rq4-gjwc","kind":"vulnerability","aliases":["GHSA-2p2f-4rq4-gjwc"],"related":[],"title":"Possible XSS vulnerability in Action View text helpers","description":"### Impact\nWith the HTML5 sanitizer (`Rails::HTML5::Sanitizer`, the default vendor on CRuby for applications using `load_defaults 7.1` or later), Nokogiri before 1.19.5 serializes `<` and `>` unescaped inside attribute values. The Action View text helpers `highlight` and `simple_format` sanitize their input and then process the resulting HTML as a string: `highlight` splits it on tag boundaries to insert matches, and `simple_format` splits it into paragraphs on blank lines. An unescaped `>` or a blank line inside an attribute value could cause markup in that value, which the sanitizer left inert, to be emitted as live elements in the helper's `html_safe` output, possibly leading to XSS. Applications that use the HTML5 sanitizer and pass untrusted text to `highlight`, or to `simple_format` with `html_options`, are affected.\n\n### Details\nThe fixed releases require rails-html-sanitizer 1.7.2 or later, which requires Loofah 2.25.3 and Nokogiri 1.19.5. With these versions, the HTML5 sanitizer escapes `<` and `>` in attribute values as `&lt;` and `&gt;`, as the HTML4 sanitizer already does. The parsed DOM is unchanged, but code or tests that compare sanitized HTML as a string may see the new serialization.\n\n### Workarounds\nUpgrade Nokogiri to 1.19.5 or later; the escaping is in its HTML5 serializer, so no Rails upgrade is needed. Alternatively, use the HTML4 sanitizer by setting `config.action_view.sanitizer_vendor = Rails::HTML4::Sanitizer`.\n\n### Releases\nThe fixed releases are available at the normal locations.\n\nPatches for those who cannot upgrade at once:\n- 8.1: https://github.com/rails/rails/commit/adc3a32d4abea77ed3aacf6f5fb71cfc005bef73.patch\n- 8.0: https://github.com/rails/rails/commit/009ea68342d05d02087c04dae7faaa4e4c1def11.patch\n\n### Credit\nThis issue was responsibly reported by HackerOne researcher [azaran](https://hackerone.com/azaran).\nThis issue was also found by the Anthropic OSS Scanner (ANT-2026-RTK47OH0).","summary":"Action View's highlight and simple_format helpers can turn sanitized attribute values back into live markup when the HTML5 sanitizer is used, because Nokogiri serializes < and > unescaped. An attacker who supplies untrusted text to these helpers can inject elements that run script in a victim's browser.","severity":"medium","cvss":6.1,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"actionview","fixed":["8.1.4.1"],"affected":">= 8.1, < 8.1.4.1","ecosystem":"rubygems"},{"name":"actionview","fixed":["8.0.5.2"],"affected":"< 8.0.5.2","ecosystem":"rubygems"}],"ecosystems":["rubygems"],"tags":["actionview","cwe-79","package","rails","ruby","self-hosted"],"not_affected_if":["auth-required","html4-sanitizer","no-untrusted-input"],"how_to_check":"- Check the Rails version in `Gemfile.lock` for `actionview` and whether it is below `8.1.4.1` or below `8.0.5.2`.\n- Check the Nokogiri version in `Gemfile.lock`; it is affected if below `1.19.5`.\n- Check whether the app uses `load_defaults 7.1` or later with the default HTML5 sanitizer, and whether it passes untrusted text to `highlight` or `simple_format` with `html_options`.","fix":"- `actionview` 8.1 series: `8.1.4.1`\n- `actionview` 8.0 series: `8.0.5.2`\n- Nokogiri: `1.19.5` or later (per the advisory, no Rails upgrade needed for this route)\n- Alternative: set `config.action_view.sanitizer_vendor = Rails::HTML4::Sanitizer`","status":"open","published_at":"2026-11-04T03:01:56+00:00","first_seen_at":"2026-11-09T22:53:29+00:00","triaged_at":"2026-11-09T22:55:09+00:00","updated_at":"2026-11-09T22:55:09+00:00","category":"package","confidence":0.8,"triage":{"at":"2026-11-09T22:55:09Z","model":"claude-haiku-5-5","output":{"fix":"- `actionview` 8.1 series: `8.1.4.1`\n- `actionview` 8.0 series: `8.0.5.2`\n- Nokogiri: `1.19.5` or later (per the advisory, no Rails upgrade needed for this route)\n- Alternative: set `config.action_view.sanitizer_vendor = Rails::HTML4::Sanitizer`","reach":"internet","title":"Rails Action View: text helpers can emit live HTML, enabling XSS","impact":"medium","summary":"Action View's highlight and simple_format helpers can turn sanitized attribute values back into live markup when the HTML5 sanitizer is used, because Nokogiri serializes < and > unescaped. An attacker who supplies untrusted text to these helpers can inject elements that run script in a victim's browser.","audience":"developers","category":"package","nicknames":[],"who_cares":["rails","actionview","ruby","self-hosted"],"confidence":0.8,"fix_status":"available","needs_auth":"unknown","worst_case":"Attacker runs script in users' browsers through injected markup.","analyst_note":"","how_to_check":"- Check the Rails version in `Gemfile.lock` for `actionview` and whether it is below `8.1.4.1` or below `8.0.5.2`.\n- Check the Nokogiri version in `Gemfile.lock`; it is affected if below `1.19.5`.\n- Check whether the app uses `load_defaults 7.1` or later with the default HTML5 sanitizer, and whether it passes untrusted text to `highlight` or `simple_format` with `html_options`.","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["html4-sanitizer","no-untrusted-input","auth-required"],"who_is_affected":"Applications built on Rails that use the HTML5 sanitizer (the default for apps with load_defaults 7.1 or later on CRuby) and pass untrusted text into highlight or simple_format with html_options. Apps that use the HTML4 sanitizer, or that do not feed untrusted text to these helpers, are not exposed.","user_interaction":"unknown","product_ecosystem":"","needs_special_setup":"yes","severity_if_unknown":"unknown"},"cost_usd":0.000917,"input_tokens":5358,"output_tokens":763,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-2026':348C '-79':23B '/azaran).':336C '/rails/rails/commit/009ea68342d05d02087c04dae7faaa4e4c1def11.patch':323C '/rails/rails/commit/adc3a32d4abea77ed3aacf6f5fb71cfc005bef73.patch':319C '1.19.5':101C,225C,270C '1.7.2':216C '2.25.3':222C '2p2f':11A,16A '4rq4':12A,17A '7.1':96C '8.0':320C '8.1':316C 'action':5A,30B,109C 'actionview':19A,20A,21B 'affect':206C 'alreadi':243C 'also':340C 'altern':286C 'ant':347C 'anthrop':344C 'applic':92C,186C 'attack':59B 'attribut':41B,106C,156C,235C 'avail':303C 'azaran':333C 'back':43B 'blank':146C,152C 'boundari':134C 'browser':77B 'cannot':312C 'caus':159C 'code':251C 'compar':255C 'config.action_view.sanitizer':293C 'could':158C 'credit':324C 'crubi':90C 'cwe':22B 'default':87C,95C 'detail':207C 'dom':247C 'element':69B,174C 'emit':171C 'escap':232C,274C 'fix':209C,300C 'format':36B,116C,140C,201C 'found':341C 'ghsa':10A,15A 'ghsa-2p2f-4rq4-gjwc':9A,14A 'github.com':318C,322C 'github.com/rails/rails/commit/009ea68342d05d02087c04dae7faaa4e4c1def11.patch':321C 'github.com/rails/rails/commit/adc3a32d4abea77ed3aacf6f5fb71cfc005bef73.patch':317C 'gjwc':13A,18A 'hackeron':331C 'hackerone.com':335C 'hackerone.com/azaran).':334C 'helper':8A,37B,66B,112C,177C 'highlight':33B,113C,129C,197C 'host':29B 'html':125C,179C,203C,214C,257C 'html4':241C,289C,296C 'html5':49B,81C,84C,190C,230C,278C 'impact':78C 'inert':168C 'inject':68B 'input':119C 'insert':136C 'insid':105C,154C 'issu':326C,338C 'later':98C,218C,272C 'lead':183C 'left':167C 'line':147C,153C 'live':45B,173C 'load':94C 'locat':307C 'loofah':221C 'markup':46B,160C 'match':137C 'may':261C 'need':285C 'new':264C 'nokogiri':54B,99C,224C,268C 'normal':306C 'option':204C 'oss':345C 'output':181C 'packag':24B 'paragraph':144C 'pars':246C 'pass':193C 'patch':308C 'possibl':1A,182C 'process':122C 'rail':25B,83C,213C,282C,295C 'rails-html-sanit':212C 'releas':210C,298C,301C 'report':329C 'requir':211C,220C 'research':332C 'respons':328C 'result':124C 'rtk47oh0':349C 'rubi':26B 'run':71B 'safe':180C 'sanit':40B,50B,82C,85C,117C,166C,191C,215C,231C,242C,256C,290C,297C 'scanner':346C 'script':72B 'see':262C 'self':28B 'self-host':27B 'serial':55B,102C,265C,279C 'set':292C 'simpl':35B,115C,139C,200C 'split':130C,141C 'string':128C,260C 'suppli':61B 'tag':133C 'test':253C 'text':7A,63B,111C,195C 'turn':39B 'unchang':249C 'unescap':57B,104C,149C 'untrust':62B,194C 'upgrad':267C,283C,313C 'use':52B,93C,188C,287C 'valu':42B,107C,157C,163C,236C 'vendor':88C,294C 'version':228C 'victim':75B 'view':6A,31B,110C 'vulner':3A 'workaround':266C 'xss':2A,185C","nicknames":[],"mitigations":[],"who_affected":"Applications built on Rails that use the HTML5 sanitizer (the default for apps with load_defaults 7.1 or later on CRuby) and pass untrusted text into highlight or simple_format with html_options. Apps that use the HTML4 sanitizer, or that do not feed untrusted text to these helpers, are not exposed.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":["actionview"],"ptokens":["actionview"],"labels":["actionview","cwe79","medium","package","rails","ruby","rubygems","selfhosted"],"campaign_type":null,"search_a":"'2p2f':11A,16A '4rq4':12A,17A 'action':5A 'actionview':19A,20A 'ghsa':10A,15A 'ghsa-2p2f-4rq4-gjwc':9A,14A 'gjwc':13A,18A 'helper':8A 'possibl':1A 'text':7A 'view':6A 'vulner':3A 'xss':2A","search_b":"'-79':23B 'action':30B 'actionview':21B 'attack':59B 'attribut':41B 'back':43B 'browser':77B 'cwe':22B 'element':69B 'format':36B 'helper':37B,66B 'highlight':33B 'host':29B 'html5':49B 'inject':68B 'live':45B 'markup':46B 'nokogiri':54B 'packag':24B 'rail':25B 'rubi':26B 'run':71B 'sanit':40B,50B 'script':72B 'self':28B 'self-host':27B 'serial':55B 'simpl':35B 'suppli':61B 'text':63B 'turn':39B 'unescap':57B 'untrust':62B 'use':52B 'valu':42B 'victim':75B 'view':31B","search_c":"'-2026':348C '/azaran).':336C '/rails/rails/commit/009ea68342d05d02087c04dae7faaa4e4c1def11.patch':323C '/rails/rails/commit/adc3a32d4abea77ed3aacf6f5fb71cfc005bef73.patch':319C '1.19.5':101C,225C,270C '1.7.2':216C '2.25.3':222C '7.1':96C '8.0':320C '8.1':316C 'action':109C 'affect':206C 'alreadi':243C 'also':340C 'altern':286C 'ant':347C 'anthrop':344C 'applic':92C,186C 'attribut':106C,156C,235C 'avail':303C 'azaran':333C 'blank':146C,152C 'boundari':134C 'cannot':312C 'caus':159C 'code':251C 'compar':255C 'config.action_view.sanitizer':293C 'could':158C 'credit':324C 'crubi':90C 'default':87C,95C 'detail':207C 'dom':247C 'element':174C 'emit':171C 'escap':232C,274C 'fix':209C,300C 'format':116C,140C,201C 'found':341C 'github.com':318C,322C 'github.com/rails/rails/commit/009ea68342d05d02087c04dae7faaa4e4c1def11.patch':321C 'github.com/rails/rails/commit/adc3a32d4abea77ed3aacf6f5fb71cfc005bef73.patch':317C 'hackeron':331C 'hackerone.com':335C 'hackerone.com/azaran).':334C 'helper':112C,177C 'highlight':113C,129C,197C 'html':125C,179C,203C,214C,257C 'html4':241C,289C,296C 'html5':81C,84C,190C,230C,278C 'impact':78C 'inert':168C 'input':119C 'insert':136C 'insid':105C,154C 'issu':326C,338C 'later':98C,218C,272C 'lead':183C 'left':167C 'line':147C,153C 'live':173C 'load':94C 'locat':307C 'loofah':221C 'markup':160C 'match':137C 'may':261C 'need':285C 'new':264C 'nokogiri':99C,224C,268C 'normal':306C 'option':204C 'oss':345C 'output':181C 'paragraph':144C 'pars':246C 'pass':193C 'patch':308C 'possibl':182C 'process':122C 'rail':83C,213C,282C,295C 'rails-html-sanit':212C 'releas':210C,298C,301C 'report':329C 'requir':211C,220C 'research':332C 'respons':328C 'result':124C 'rtk47oh0':349C 'safe':180C 'sanit':82C,85C,117C,166C,191C,215C,231C,242C,256C,290C,297C 'scanner':346C 'see':262C 'serial':102C,265C,279C 'set':292C 'simpl':115C,139C,200C 'split':130C,141C 'string':128C,260C 'tag':133C 'test':253C 'text':111C,195C 'unchang':249C 'unescap':104C,149C 'untrust':194C 'upgrad':267C,283C,313C 'use':93C,188C,287C 'valu':107C,157C,163C,236C 'vendor':88C,294C 'version':228C 'view':110C 'workaround':266C 'xss':185C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-11-04T03:01:56+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"ghsa-repo","external_id":"GHSA-2p2f-4rq4-gjwc","url":"https://github.com/rails/rails/security/advisories/GHSA-2p2f-4rq4-gjwc","severity":"medium","published_at":"2026-11-04T03:01:56+00:00","modified_at":"2026-11-04T03:01:56+00:00","first_seen_at":"2026-11-09T22:53:29+00:00","fetched_at":"2026-11-09T22:53:29+00:00","note":null}],"documents":[{"id":110681,"url":"https://github.com/rails/rails/security/advisories/GHSA-2p2f-4rq4-gjwc","title":"Maintainer's advisory: github.com","kind":"vendor","source":"ghsa-repo","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: 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"}