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