{"id":"CVE-2026-125108","kind":"vulnerability","aliases":["CVE-2026-125108","GHSA-p8x9-v4hv-2w4g"],"related":[],"title":"Multipart boundary guard skips a leading empty or quoted `boundary` parameter, allowing parser differentials and WAF bypass.","description":"## Summary\n\nThe guard added for CVE-2026-26961 (GHSA-vgpv-f759-9wx3), which rejects multipart requests with more than one `boundary` parameter, only inspects the part of the `Content-Type` header after the boundary it extracts. A `Content-Type` whose first `boundary` parameter is empty or begins with a quote, semicolon, or comma is skipped by the extraction pattern, so a second `boundary` parameter is accepted silently and Rack parses the body with a boundary that a conforming parser would not derive from the header.\n\n## Details\n\n`Rack::Multipart::Parser.parse_boundary` extracts the boundary with a regular expression that uses a lazy prefix and a value class excluding `\"`, `;`, and `,`. For a header such as `multipart/form-data; boundary=\";boundary=AaB03x\"` or `multipart/form-data; boundary=; boundary=AaB03x`, the pattern skips the first `boundary=` and anchors on the second, and the subsequent check for another `boundary=` in the remaining text finds nothing. Rack then uses `AaB03x`.\n\nRFC 9110 parses the first header as a single parameter whose value is `;boundary=AaB03x`, which is not a legal boundary under RFC 2046, so the only conformant outcome is rejection. Inspecting intermediaries that implement the standard grammar, such as ModSecurity, see a different boundary or no multipart body at all.\n\nThe fix counts `boundary=` occurrences across the entire header value and rejects the request when there is more than one.\n\n## Impact\n\nAs with CVE-2026-26961, an attacker can craft a multipart request that a web application firewall or other inspecting proxy in front of a Rack application interprets differently from Rack, so form fields and file uploads reach the application without inspection. Rack itself grants no capability beyond that of a well-formed request with the same body. All supported versions, including 2.2, are affected.\n\n## Mitigation\n\n* Update to a patched version of Rack.\n* Reject requests whose `Content-Type` contains more than one `boundary` parameter at the reverse proxy.","summary":"Rack's guard against multipart requests with two boundary parameters misses a Content-Type whose first boundary is empty or starts with a quote, semicolon or comma. An attacker can send a body that a web application firewall reads differently from Rack, so uploads and form fields reach the app without inspection.","severity":"low","cvss":3.7,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"rack","fixed":["2.2.25"],"affected":"< 2.2.25","ecosystem":"rubygems"},{"name":"rack","fixed":["3.1.23"],"affected":">= 3.0, < 3.1.23","ecosystem":"rubygems"},{"name":"rack","fixed":["3.2.8"],"affected":">= 3.2, < 3.2.8","ecosystem":"rubygems"}],"ecosystems":["rubygems"],"tags":["cwe-436","package","rack","rails","ruby","self-hosted"],"not_affected_if":["no-waf-in-front","proxy-rejects-multiple-boundaries"],"how_to_check":"- Check the Rack version in `Gemfile.lock` for `rack (`\n- Run `bundle exec ruby -e 'require \"rack\"; puts Rack.release'` to print the loaded version\n- Look for a WAF or inspecting proxy in front of the Rack app that filters multipart uploads","fix":"- `rack` 2.2 line: `2.2.25`\n- `rack` 3.1 line: `3.1.23`\n- `rack` 3.2 line: `3.2.8`","status":"open","published_at":"2026-10-30T02:19:00+00:00","first_seen_at":"2026-11-09T22:53:30+00:00","triaged_at":"2026-11-09T22:57:20+00:00","updated_at":"2026-11-09T22:57:20+00:00","category":"package","confidence":0.8,"triage":{"at":"2026-11-09T22:57:20Z","model":"claude-haiku-5-5","output":{"fix":"- `rack` 2.2 line: `2.2.25`\n- `rack` 3.1 line: `3.1.23`\n- `rack` 3.2 line: `3.2.8`","reach":"internet","title":"Rack: duplicate multipart boundary check lets requests slip past WAFs","impact":"low","summary":"Rack's guard against multipart requests with two boundary parameters misses a Content-Type whose first boundary is empty or starts with a quote, semicolon or comma. An attacker can send a body that a web application firewall reads differently from Rack, so uploads and form fields reach the app without inspection.","audience":"developers","category":"package","nicknames":[],"who_cares":["rack","ruby","rails","self-hosted"],"confidence":0.8,"fix_status":"available","needs_auth":"no","worst_case":"WAF inspection bypassed; uploads reach app uninspected","analyst_note":"","how_to_check":"- Check the Rack version in `Gemfile.lock` for `rack (`\n- Run `bundle exec ruby -e 'require \"rack\"; puts Rack.release'` to print the loaded version\n- Look for a WAF or inspecting proxy in front of the Rack app that filters multipart uploads","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["no-waf-in-front","proxy-rejects-multiple-boundaries"],"who_is_affected":"Applications built on Rack (Rails, Sinatra and similar) that accept multipart uploads or form posts and sit behind a WAF or inspecting proxy that relies on the standard multipart parsing. The advisory says all supported versions including 2.2 are affected. Apps with no inspecting proxy in front, or that reject multiple boundary parameters at the reverse proxy, are less exposed.","user_interaction":"no","product_ecosystem":"","needs_special_setup":"unknown","severity_if_unknown":"low"},"cost_usd":0.000857,"input_tokens":5307,"output_tokens":653,"severity_before":"low"},"analyst_status":null,"analyst_note":null,"search":"'-125108':20A,28A '-2026':19A,27A,100C,322C '-26961':101C,323C '-436':33B '2.2':382C '2046':270C '2w4g':25A '9110':248C '9wx3':106C 'aab03x':213C,218C,246C,261C 'accept':162C 'across':303C 'add':97C 'affect':384C 'allow':12A 'anchor':226C 'anoth':235C 'app':91B 'applic':78B,334C,345C,358C 'attack':70B,325C 'begin':143C 'beyond':366C 'bodi':74B,168C,295C,377C 'boundari':2A,10A,49B,58B,115C,129C,138C,159C,171C,186C,189C,211C,212C,216C,217C,224C,236C,260C,267C,291C,301C,403C 'bypass':17A 'capabl':365C 'check':233C 'class':202C 'comma':68B,149C 'conform':174C,274C 'contain':399C 'content':54B,124C,134C,397C 'content-typ':53B,123C,133C,396C 'count':300C 'craft':327C 'cve':18A,26A,99C,321C 'cwe':32B 'deriv':178C 'detail':182C 'differ':81B,290C,347C 'differenti':14A 'empti':7A,60B,141C 'entir':305C 'exclud':203C 'express':193C 'extract':131C,154C,187C 'f759':105C 'field':88B,352C 'file':354C 'find':241C 'firewal':79B,335C 'first':57B,137C,223C,251C 'fix':299C 'form':87B,351C,372C 'front':341C 'ghsa':22A,103C 'ghsa-p8x9-v4hv-2w4g':21A 'ghsa-vgpv-f759-9wx3':102C 'grammar':284C 'grant':363C 'guard':3A,43B,96C 'header':126C,181C,207C,252C,306C 'host':40B 'impact':318C 'implement':281C 'includ':381C 'inspect':93B,118C,278C,338C,360C 'intermediari':279C 'interpret':346C 'lazi':197C 'lead':6A 'legal':266C 'miss':51B 'mitig':385C 'modsecur':287C 'multipart':1A,45B,109C,184C,294C,329C 'multipart/form-data':210C,215C 'noth':242C 'occurr':302C 'one':114C,317C,402C 'outcom':275C 'p8x9':23A 'packag':34B 'paramet':11A,50B,116C,139C,160C,256C,404C 'pars':166C,249C 'parser':13A,175C 'parser.parse':185C 'part':120C 'patch':389C 'pattern':155C,220C 'prefix':198C 'proxi':339C,408C 'quot':9A,65B,146C 'rack':29A,30A,31A,35B,41B,83B,165C,183C,243C,344C,349C,361C,392C 'rail':36B 'reach':89B,356C 'read':80B 'regular':192C 'reject':108C,277C,309C,393C 'remain':239C 'request':46B,110C,311C,330C,373C,394C 'revers':407C 'rfc':247C,269C 'rubi':37B 'second':158C,229C 'see':288C 'self':39B 'self-host':38B 'semicolon':66B,147C 'send':72B 'silent':163C 'singl':255C 'skip':4A,151C,221C 'standard':283C 'start':62B 'subsequ':232C 'summari':94C 'support':379C 'text':240C 'two':48B 'type':55B,125C,135C,398C 'updat':386C 'upload':85B,355C 'use':195C,245C 'v4hv':24A 'valu':201C,258C,307C 'version':380C,390C 'vgpv':104C 'waf':16A 'web':77B,333C 'well':371C 'well-form':370C 'whose':56B,136C,257C,395C 'without':92B,359C 'would':176C","nicknames":[],"mitigations":[],"who_affected":"Applications built on Rack (Rails, Sinatra and similar) that accept multipart uploads or form posts and sit behind a WAF or inspecting proxy that relies on the standard multipart parsing. The advisory says all supported versions including 2.2 are affected. Apps with no inspecting proxy in front, or that reject multiple boundary parameters at the reverse proxy, are less exposed.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":["rack"],"ptokens":["rack"],"labels":["cwe436","low","package","rack","rails","ruby","rubygems","selfhosted"],"campaign_type":null,"search_a":"'-125108':20A,28A '-2026':19A,27A '2w4g':25A 'allow':12A 'boundari':2A,10A 'bypass':17A 'cve':18A,26A 'differenti':14A 'empti':7A 'ghsa':22A 'ghsa-p8x9-v4hv-2w4g':21A 'guard':3A 'lead':6A 'multipart':1A 'p8x9':23A 'paramet':11A 'parser':13A 'quot':9A 'rack':29A,30A,31A 'skip':4A 'v4hv':24A 'waf':16A","search_b":"'-436':33B 'app':91B 'applic':78B 'attack':70B 'bodi':74B 'boundari':49B,58B 'comma':68B 'content':54B 'content-typ':53B 'cwe':32B 'differ':81B 'empti':60B 'field':88B 'firewal':79B 'first':57B 'form':87B 'guard':43B 'host':40B 'inspect':93B 'miss':51B 'multipart':45B 'packag':34B 'paramet':50B 'quot':65B 'rack':35B,41B,83B 'rail':36B 'reach':89B 'read':80B 'request':46B 'rubi':37B 'self':39B 'self-host':38B 'semicolon':66B 'send':72B 'start':62B 'two':48B 'type':55B 'upload':85B 'web':77B 'whose':56B 'without':92B","search_c":"'-2026':100C,322C '-26961':101C,323C '2.2':382C '2046':270C '9110':248C '9wx3':106C 'aab03x':213C,218C,246C,261C 'accept':162C 'across':303C 'add':97C 'affect':384C 'anchor':226C 'anoth':235C 'applic':334C,345C,358C 'attack':325C 'begin':143C 'beyond':366C 'bodi':168C,295C,377C 'boundari':115C,129C,138C,159C,171C,186C,189C,211C,212C,216C,217C,224C,236C,260C,267C,291C,301C,403C 'capabl':365C 'check':233C 'class':202C 'comma':149C 'conform':174C,274C 'contain':399C 'content':124C,134C,397C 'content-typ':123C,133C,396C 'count':300C 'craft':327C 'cve':99C,321C 'deriv':178C 'detail':182C 'differ':290C,347C 'empti':141C 'entir':305C 'exclud':203C 'express':193C 'extract':131C,154C,187C 'f759':105C 'field':352C 'file':354C 'find':241C 'firewal':335C 'first':137C,223C,251C 'fix':299C 'form':351C,372C 'front':341C 'ghsa':103C 'ghsa-vgpv-f759-9wx3':102C 'grammar':284C 'grant':363C 'guard':96C 'header':126C,181C,207C,252C,306C 'impact':318C 'implement':281C 'includ':381C 'inspect':118C,278C,338C,360C 'intermediari':279C 'interpret':346C 'lazi':197C 'legal':266C 'mitig':385C 'modsecur':287C 'multipart':109C,184C,294C,329C 'multipart/form-data':210C,215C 'noth':242C 'occurr':302C 'one':114C,317C,402C 'outcom':275C 'paramet':116C,139C,160C,256C,404C 'pars':166C,249C 'parser':175C 'parser.parse':185C 'part':120C 'patch':389C 'pattern':155C,220C 'prefix':198C 'proxi':339C,408C 'quot':146C 'rack':165C,183C,243C,344C,349C,361C,392C 'reach':356C 'regular':192C 'reject':108C,277C,309C,393C 'remain':239C 'request':110C,311C,330C,373C,394C 'revers':407C 'rfc':247C,269C 'second':158C,229C 'see':288C 'semicolon':147C 'silent':163C 'singl':255C 'skip':151C,221C 'standard':283C 'subsequ':232C 'summari':94C 'support':379C 'text':240C 'type':125C,135C,398C 'updat':386C 'upload':355C 'use':195C,245C 'valu':201C,258C,307C 'version':380C,390C 'vgpv':104C 'web':333C 'well':371C 'well-form':370C 'whose':136C,257C,395C 'without':359C 'would':176C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-10-30T02:19:00+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"ghsa-repo","external_id":"GHSA-p8x9-v4hv-2w4g","url":"https://github.com/rack/rack/security/advisories/GHSA-p8x9-v4hv-2w4g","severity":"low","published_at":"2026-10-30T02:19:00+00:00","modified_at":"2026-11-09T21:54:15+00:00","first_seen_at":"2026-11-09T22:53:30+00:00","fetched_at":"2026-11-09T22:53:30+00:00","note":null}],"documents":[{"id":110686,"url":"https://github.com/rack/rack/security/advisories/GHSA-p8x9-v4hv-2w4g","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"}