|
| 1 | +--- |
| 2 | +gem: rack |
| 3 | +cve: 2026-32762 |
| 4 | +ghsa: qfgr-crr9-7r49 |
| 5 | +url: https://github.com/rack/rack/security/advisories/GHSA-qfgr-crr9-7r49 |
| 6 | +title: Rack - Forwarded Header semicolon injection enables |
| 7 | + Host and Scheme spoofing |
| 8 | +date: 2026-04-02 |
| 9 | +description: | |
| 10 | + ## Summary |
| 11 | +
|
| 12 | + `Rack::Utils.forwarded_values` parses the RFC 7239 `Forwarded` header |
| 13 | + by splitting on semicolons before handling quoted-string values. |
| 14 | + Because quoted values may legally contain semicolons, a header such as: |
| 15 | +
|
| 16 | + ```http |
| 17 | + Forwarded: for="127.0.0.1;host=evil.com;proto=https" |
| 18 | + ``` |
| 19 | +
|
| 20 | + can be interpreted by Rack as multiple `Forwarded` directives rather |
| 21 | + than as a single quoted `for` value. |
| 22 | +
|
| 23 | + In deployments where an upstream proxy, WAF, or intermediary validates |
| 24 | + or preserves quoted `Forwarded` values differently, this discrepancy |
| 25 | + can allow an attacker to smuggle `host`, `proto`, `for`, or `by` |
| 26 | + parameters through a single header value. |
| 27 | +
|
| 28 | + ## Details |
| 29 | +
|
| 30 | + `Rack::Utils.forwarded_values` processes the header using logic |
| 31 | + equivalent to: |
| 32 | +
|
| 33 | + ```ruby |
| 34 | + forwarded_header.split(';').each_with_object({}) do |field, values| |
| 35 | + field.split(',').each do |pair| |
| 36 | + pair = pair.split('=').map(&:strip).join('=') |
| 37 | + return nil unless pair =~ /\A(by|for|host|proto)="?([^"]+)"?\Z/i |
| 38 | + (values[$1.downcase.to_sym] ||= []) << $2 |
| 39 | + end |
| 40 | + end |
| 41 | + ``` |
| 42 | +
|
| 43 | + The method splits on `;` before it parses individual `name=value` |
| 44 | + pairs. This is inconsistent with RFC 7239, which permits quoted-string |
| 45 | + values, and quoted strings may contain semicolons as literal content. |
| 46 | +
|
| 47 | + As a result, a header value such as: |
| 48 | +
|
| 49 | + ```http |
| 50 | + Forwarded: for="127.0.0.1;host=evil.com;proto=https" |
| 51 | + ``` |
| 52 | +
|
| 53 | + is not treated as a single `for` value. Instead, Rack may interpret |
| 54 | + it as if the client had supplied separate `for`, `host`, and `proto` |
| 55 | + directives. |
| 56 | +
|
| 57 | + This creates an interpretation conflict when another component in |
| 58 | + front of Rack treats the quoted value as valid literal content, |
| 59 | + while Rack reparses it as multiple forwarding parameters. |
| 60 | +
|
| 61 | + ## Impact |
| 62 | +
|
| 63 | + Applications that rely on `Forwarded` to derive request metadata |
| 64 | + may observe attacker-controlled values for `host`, `proto`, `for`, |
| 65 | + or related URL components. |
| 66 | +
|
| 67 | + In affected deployments, this can lead to host or scheme spoofing |
| 68 | + in derived values such as `req.host`, `req.scheme`, `req.base_url`, |
| 69 | + or `req.url`. Applications that use those values for password reset |
| 70 | + links, redirects, absolute URL generation, logging, IP-based |
| 71 | + decisions, or backend requests may be vulnerable to downstream |
| 72 | + security impact. |
| 73 | +
|
| 74 | + The practical security impact depends on deployment architecture. |
| 75 | + If clients can already supply arbitrary trusted `Forwarded` |
| 76 | + parameters directly, this bug may not add meaningful attacker |
| 77 | + capability. The issue is most relevant where an upstream component |
| 78 | + and Rack interpret the same `Forwarded` header differently. |
| 79 | +
|
| 80 | + ## Mitigation |
| 81 | +
|
| 82 | + * Update to a patched version of Rack that parses `Forwarded` |
| 83 | + quoted-string values before splitting on parameter delimiters. |
| 84 | + * Avoid trusting client-supplied `Forwarded` headers unless they |
| 85 | + are normalized or regenerated by a trusted reverse proxy. |
| 86 | + * Prefer stripping inbound `Forwarded` headers at the edge and |
| 87 | + reconstructing them from trusted proxy metadata. |
| 88 | + * Avoid using `req.host`, `req.scheme`, `req.base_url`, or |
| 89 | + `req.url` for security-sensitive operations unless the forwarding |
| 90 | + chain is explicitly trusted and validated. |
| 91 | +cvss_v3: 4.8 |
| 92 | +unaffected_versions: |
| 93 | + - "< 3.0.0.beta1" |
| 94 | +patched_versions: |
| 95 | + - "~> 3.1.21" |
| 96 | + - ">= 3.2.6" |
| 97 | +related: |
| 98 | + url: |
| 99 | + - https://nvd.nist.gov/vuln/detail/CVE-2026-32762 |
| 100 | + - https://github.com/rack/rack/security/advisories/GHSA-qfgr-crr9-7r49 |
| 101 | + - https://github.com/advisories/GHSA-qfgr-crr9-7r49 |
0 commit comments