{"id":"GHSA-v6rj-xm57-3p59","kind":"vulnerability","aliases":["GHSA-v6rj-xm57-3p59"],"related":[],"title":"Possible XSS vulnerability in Action View highlight helper","description":"### Impact\n`ActionView::Helpers::TextHelper#highlight` substitutes each matched phrase into the `:highlighter` string without escaping it and returns the result marked HTML-safe. Because sanitizing leaves quote characters in text unescaped, a match substituted into a quoted attribute value of the highlighter, such as the `<a href=\"search?q=\\1\">` form shown in the method's documentation, could end the attribute value and add attributes to the element, possibly leading to XSS. Applications are affected when they pass a `:highlighter` that places a placeholder inside an attribute value and highlight text or phrases that a user controls. The default `<mark>\\1</mark>` highlighter and the block form are not affected.\n\n### Details\nThe fixed releases HTML-escape each group substituted into the `:highlighter` string, so quotes in a match are rendered as `&quot;` and `&#39;`. Only the numbered placeholders `\\0` to `\\9` are expanded; other `String#sub` replacement escapes, such as `\\k<name>`, `\\&` and `\\\\`, are left as written. A match can no longer begin on the `>` that closes a preceding tag. Escaping makes a placeholder safe as element content or inside a quoted attribute value, but not in an unquoted attribute value, a URL, JavaScript or CSS context, or an attribute whose value is HTML. See the Action View CHANGELOG for details.\n\n### Workarounds\nUse a `:highlighter` that places the matched phrase only in element content, such as the default `<mark>\\1</mark>`.\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/06938194b4fd59e1d2c8ab4a781f3c1e2b763425.patch\n- 8.0: https://github.com/rails/rails/commit/c796f6198837479ada13290eb8fa767b5219a58a.patch\n\n### Credit\nThis issue was found by the Anthropic OSS Scanner (ANT-2026-THHUJQVO).","summary":"The Action View highlight helper inserts matched text into a custom :highlighter string without escaping and marks the result HTML-safe. An attacker who controls highlighted text can break out of a quoted attribute and add attributes to the element, leading to cross-site scripting.","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-on-rails","self-hosted"],"not_affected_if":["block-form","default-highlighter","element-content-only"],"how_to_check":"- Search application code for `highlight(` calls that pass a `:highlighter` option.\n- Check whether that highlighter places `\\1` or another placeholder inside an attribute value, such as `<a href=\"...\\1\">`.\n- Check the installed `actionview` version, e.g. `bundle exec gem list actionview`, against the fixed versions below.","fix":"- actionview 8.1 series: `8.1.4.1`\n- actionview 8.0 series: `8.0.5.2`\n- Patches for those who cannot upgrade are linked in the advisory for 8.1 and 8.0.","status":"open","published_at":"2026-11-04T03:02:12+00:00","first_seen_at":"2026-11-09T22:53:29+00:00","triaged_at":"2026-11-09T22:55:05+00:00","updated_at":"2026-11-09T22:55:05+00:00","category":"package","confidence":0.85,"triage":{"at":"2026-11-09T22:55:05Z","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- Patches for those who cannot upgrade are linked in the advisory for 8.1 and 8.0.","reach":"internet","title":"Rails Action View: highlight helper XSS with custom highlighter attributes","impact":"medium","summary":"The Action View highlight helper inserts matched text into a custom :highlighter string without escaping and marks the result HTML-safe. An attacker who controls highlighted text can break out of a quoted attribute and add attributes to the element, leading to cross-site scripting.","audience":"developers","category":"package","nicknames":[],"who_cares":["rails","actionview","ruby-on-rails","self-hosted"],"confidence":0.85,"fix_status":"available","needs_auth":"unknown","worst_case":"attacker runs script in victims' browsers via attributes","analyst_note":"","how_to_check":"- Search application code for `highlight(` calls that pass a `:highlighter` option.\n- Check whether that highlighter places `\\1` or another placeholder inside an attribute value, such as `<a href=\"...\\1\">`.\n- Check the installed `actionview` version, e.g. `bundle exec gem list actionview`, against the fixed versions below.","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["default-highlighter","block-form","element-content-only"],"who_is_affected":"Applications that call Action View's highlight helper with a custom :highlighter that puts the placeholder inside an attribute value, and that highlight user-controlled text. The default <mark>\\1</mark> highlighter and the block form are not affected, and neither is any use that keeps the placeholder in element content.","user_interaction":"unknown","product_ecosystem":"","needs_special_setup":"yes","severity_if_unknown":"unknown"},"cost_usd":0.000845,"input_tokens":5244,"output_tokens":642,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-2026':338C '-79':23B '/rails/rails/commit/06938194b4fd59e1d2c8ab4a781f3c1e2b763425.patch':322C '/rails/rails/commit/c796f6198837479ada13290eb8fa767b5219a58a.patch':326C '0':211C '1':175C,300C '3p59':13A,18A '8.0':323C '8.1':319C '9':213C 'action':5A,34B,278C 'actionview':19A,20A,21B,81C 'add':69B,139C 'affect':150C,183C 'ant':337C 'anthrop':334C 'applic':148C 'attack':56B 'attribut':67B,70B,118C,136C,140C,162C,254C,261C,271C 'avail':306C 'begin':234C 'block':179C 'break':62B 'cannot':315C 'changelog':280C 'charact':108C 'close':238C 'content':249C,295C 'context':268C 'control':58B,172C 'could':133C 'credit':327C 'cross':77B 'cross-sit':76B 'css':267C 'custom':43B 'cwe':22B 'default':174C,299C 'detail':184C,282C 'document':132C 'element':73B,143C,248C,294C 'end':134C 'escap':47B,94C,190C,220C,242C 'expand':215C 'fix':186C,303C 'form':126C,180C 'found':331C 'ghsa':10A,15A 'ghsa-v6rj-xm57-3p59':9A,14A 'github.com':321C,325C 'github.com/rails/rails/commit/06938194b4fd59e1d2c8ab4a781f3c1e2b763425.patch':320C 'github.com/rails/rails/commit/c796f6198837479ada13290eb8fa767b5219a58a.patch':324C 'group':192C 'helper':8A,37B,82C 'highlight':7A,36B,44B,59B,84C,91C,122C,155C,165C,176C,196C,286C 'host':32B 'html':53B,102C,189C,275C 'html-escap':188C 'html-safe':52B,101C 'impact':80C 'insert':38B 'insid':160C,251C 'issu':329C 'javascript':265C 'k':223C 'lead':74B,145C 'leav':106C 'left':226C 'locat':310C 'longer':233C 'make':243C 'mark':49B,100C 'match':39B,87C,113C,202C,230C,290C 'method':130C 'normal':309C 'number':209C 'oss':335C 'packag':24B 'pass':153C 'patch':311C 'phrase':88C,168C,291C 'place':157C,288C 'placehold':159C,210C,245C 'possibl':1A,144C 'preced':240C 'quot':66B,107C,117C,199C,253C 'rail':25B,29B 'releas':187C,301C,304C 'render':204C 'replac':219C 'result':51B,99C 'return':97C 'rubi':27B 'ruby-on-rail':26B 'safe':54B,103C,246C 'sanit':105C 'scanner':336C 'script':79B 'see':276C 'self':31B 'self-host':30B 'shown':127C 'site':78B 'string':45B,92C,197C,217C 'sub':218C 'substitut':85C,114C,193C 'tag':241C 'text':40B,60B,110C,166C 'texthelp':83C 'thhujqvo':339C 'unescap':111C 'unquot':260C 'upgrad':316C 'url':264C 'use':284C 'user':171C 'v6rj':11A,16A 'valu':119C,137C,163C,255C,262C,273C 'view':6A,35B,279C 'vulner':3A 'whose':272C 'without':46B,93C 'workaround':283C 'written':228C 'xm57':12A,17A 'xss':2A,147C","nicknames":[],"mitigations":[],"who_affected":"Applications that call Action View's highlight helper with a custom :highlighter that puts the placeholder inside an attribute value, and that highlight user-controlled text. The default <mark>\\1</mark> highlighter and the block form are not affected, and neither is any use that keeps the placeholder in element content.","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","rubygems","rubyonrails","selfhosted"],"campaign_type":null,"search_a":"'3p59':13A,18A 'action':5A 'actionview':19A,20A 'ghsa':10A,15A 'ghsa-v6rj-xm57-3p59':9A,14A 'helper':8A 'highlight':7A 'possibl':1A 'v6rj':11A,16A 'view':6A 'vulner':3A 'xm57':12A,17A 'xss':2A","search_b":"'-79':23B 'action':34B 'actionview':21B 'add':69B 'attack':56B 'attribut':67B,70B 'break':62B 'control':58B 'cross':77B 'cross-sit':76B 'custom':43B 'cwe':22B 'element':73B 'escap':47B 'helper':37B 'highlight':36B,44B,59B 'host':32B 'html':53B 'html-safe':52B 'insert':38B 'lead':74B 'mark':49B 'match':39B 'packag':24B 'quot':66B 'rail':25B,29B 'result':51B 'rubi':27B 'ruby-on-rail':26B 'safe':54B 'script':79B 'self':31B 'self-host':30B 'site':78B 'string':45B 'text':40B,60B 'view':35B 'without':46B","search_c":"'-2026':338C '/rails/rails/commit/06938194b4fd59e1d2c8ab4a781f3c1e2b763425.patch':322C '/rails/rails/commit/c796f6198837479ada13290eb8fa767b5219a58a.patch':326C '0':211C '1':175C,300C '8.0':323C '8.1':319C '9':213C 'action':278C 'actionview':81C 'add':139C 'affect':150C,183C 'ant':337C 'anthrop':334C 'applic':148C 'attribut':118C,136C,140C,162C,254C,261C,271C 'avail':306C 'begin':234C 'block':179C 'cannot':315C 'changelog':280C 'charact':108C 'close':238C 'content':249C,295C 'context':268C 'control':172C 'could':133C 'credit':327C 'css':267C 'default':174C,299C 'detail':184C,282C 'document':132C 'element':143C,248C,294C 'end':134C 'escap':94C,190C,220C,242C 'expand':215C 'fix':186C,303C 'form':126C,180C 'found':331C 'github.com':321C,325C 'github.com/rails/rails/commit/06938194b4fd59e1d2c8ab4a781f3c1e2b763425.patch':320C 'github.com/rails/rails/commit/c796f6198837479ada13290eb8fa767b5219a58a.patch':324C 'group':192C 'helper':82C 'highlight':84C,91C,122C,155C,165C,176C,196C,286C 'html':102C,189C,275C 'html-escap':188C 'html-safe':101C 'impact':80C 'insid':160C,251C 'issu':329C 'javascript':265C 'k':223C 'lead':145C 'leav':106C 'left':226C 'locat':310C 'longer':233C 'make':243C 'mark':100C 'match':87C,113C,202C,230C,290C 'method':130C 'normal':309C 'number':209C 'oss':335C 'pass':153C 'patch':311C 'phrase':88C,168C,291C 'place':157C,288C 'placehold':159C,210C,245C 'possibl':144C 'preced':240C 'quot':107C,117C,199C,253C 'releas':187C,301C,304C 'render':204C 'replac':219C 'result':99C 'return':97C 'safe':103C,246C 'sanit':105C 'scanner':336C 'see':276C 'shown':127C 'string':92C,197C,217C 'sub':218C 'substitut':85C,114C,193C 'tag':241C 'text':110C,166C 'texthelp':83C 'thhujqvo':339C 'unescap':111C 'unquot':260C 'upgrad':316C 'url':264C 'use':284C 'user':171C 'valu':119C,137C,163C,255C,262C,273C 'view':279C 'whose':272C 'without':93C 'workaround':283C 'written':228C 'xss':147C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-11-04T03:02:12+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"ghsa-repo","external_id":"GHSA-v6rj-xm57-3p59","url":"https://github.com/rails/rails/security/advisories/GHSA-v6rj-xm57-3p59","severity":"medium","published_at":"2026-11-04T03:02:12+00:00","modified_at":"2026-11-04T03:02:12+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":110667,"url":"https://github.com/rails/rails/security/advisories/GHSA-v6rj-xm57-3p59","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"}