{"id":"GHSA-qfgr-crr9-7r49","summary":"Rack: Forwarded Header semicolon injection enables Host and Scheme spoofing","details":"## Summary\n\n`Rack::Utils.forwarded_values` parses the RFC 7239 `Forwarded` header by splitting on semicolons before handling quoted-string values. Because quoted values may legally contain semicolons, a header such as:\n\n```http\nForwarded: for=\"127.0.0.1;host=evil.com;proto=https\"\n```\n\ncan be interpreted by Rack as multiple `Forwarded` directives rather than as a single quoted `for` value.\n\nIn deployments where an upstream proxy, WAF, or intermediary validates or preserves quoted `Forwarded` values differently, this discrepancy can allow an attacker to smuggle `host`, `proto`, `for`, or `by` parameters through a single header value.\n\n## Details\n\n`Rack::Utils.forwarded_values` processes the header using logic equivalent to:\n\n```ruby\nforwarded_header.split(';').each_with_object({}) do |field, values|\n  field.split(',').each do |pair|\n    pair = pair.split('=').map(&:strip).join('=')\n    return nil unless pair =~ /\\A(by|for|host|proto)=\"?([^\"]+)\"?\\Z/i\n    (values[$1.downcase.to_sym] ||= []) \u003c\u003c $2\n  end\nend\n```\n\nThe method splits on `;` before it parses individual `name=value` pairs. This is inconsistent with RFC 7239, which permits quoted-string values, and quoted strings may contain semicolons as literal content.\n\nAs a result, a header value such as:\n\n```http\nForwarded: for=\"127.0.0.1;host=evil.com;proto=https\"\n```\n\nis not treated as a single `for` value. Instead, Rack may interpret it as if the client had supplied separate `for`, `host`, and `proto` directives.\n\nThis creates an interpretation conflict when another component in front of Rack treats the quoted value as valid literal content, while Rack reparses it as multiple forwarding parameters.\n\n## Impact\n\nApplications that rely on `Forwarded` to derive request metadata may observe attacker-controlled values for `host`, `proto`, `for`, or related URL components.\n\nIn affected deployments, this can lead to host or scheme spoofing in derived values such as `req.host`, `req.scheme`, `req.base_url`, or `req.url`. Applications that use those values for password reset links, redirects, absolute URL generation, logging, IP-based decisions, or backend requests may be vulnerable to downstream security impact.\n\nThe practical security impact depends on deployment architecture. If clients can already supply arbitrary trusted `Forwarded` parameters directly, this bug may not add meaningful attacker capability. The issue is most relevant where an upstream component and Rack interpret the same `Forwarded` header differently.\n\n## Mitigation\n\n* Update to a patched version of Rack that parses `Forwarded` quoted-string values before splitting on parameter delimiters.\n* Avoid trusting client-supplied `Forwarded` headers unless they are normalized or regenerated by a trusted reverse proxy.\n* Prefer stripping inbound `Forwarded` headers at the edge and reconstructing them from trusted proxy metadata.\n* Avoid using `req.host`, `req.scheme`, `req.base_url`, or `req.url` for security-sensitive operations unless the forwarding chain is explicitly trusted and validated.","aliases":["CVE-2026-32762"],"modified":"2026-05-13T16:39:13.688697Z","published":"2026-04-02T20:31:52Z","related":["CGA-39jg-9vr8-xm6f"],"database_specific":{"cwe_ids":["CWE-436"],"github_reviewed":true,"github_reviewed_at":"2026-04-02T20:31:52Z","severity":"MODERATE","nvd_published_at":"2026-04-02T18:16:27Z"},"references":[{"type":"WEB","url":"https://github.com/rack/rack/security/advisories/GHSA-qfgr-crr9-7r49"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-32762"},{"type":"PACKAGE","url":"https://github.com/rack/rack"},{"type":"WEB","url":"https://github.com/rubysec/ruby-advisory-db/blob/master/gems/rack/CVE-2026-32762.yml"}],"affected":[{"package":{"name":"rack","ecosystem":"RubyGems","purl":"pkg:gem/rack"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.0.0.beta1"},{"fixed":"3.1.21"}]}],"versions":["3.0.0","3.0.0.beta1","3.0.0.rc1","3.0.1","3.0.10","3.0.11","3.0.12","3.0.13","3.0.14","3.0.15","3.0.16","3.0.17","3.0.18","3.0.2","3.0.3","3.0.4","3.0.4.1","3.0.4.2","3.0.5","3.0.6","3.0.6.1","3.0.7","3.0.8","3.0.9","3.0.9.1","3.1.0","3.1.1","3.1.10","3.1.11","3.1.12","3.1.13","3.1.14","3.1.15","3.1.16","3.1.17","3.1.18","3.1.19","3.1.2","3.1.20","3.1.3","3.1.4","3.1.5","3.1.6","3.1.7","3.1.8","3.1.9"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/04/GHSA-qfgr-crr9-7r49/GHSA-qfgr-crr9-7r49.json"}},{"package":{"name":"rack","ecosystem":"RubyGems","purl":"pkg:gem/rack"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.2.0"},{"fixed":"3.2.6"}]}],"versions":["3.2.0","3.2.1","3.2.2","3.2.3","3.2.4","3.2.5"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/04/GHSA-qfgr-crr9-7r49/GHSA-qfgr-crr9-7r49.json"}}],"schema_version":"1.7.5","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N"}]}