GitHub Security Advisory: GHSA-qfgr-crr9-7r49
Package: rack (RUBYGEMS)
Severity: MODERATE (CVSS 4.8)
CWE: CWE-436: Interpretation Conflict
Vulnerable versions: >= 3.0.0.beta1, < 3.1.21
Patched in: 3.1.21

Summary: Rack: Forwarded Header semicolon injection enables Host and Scheme spoofing

Details:
## Summary

`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:

```http
Forwarded: for="127.0.0.1;host=evil.com;proto=https"
```

can be interpreted by Rack as multiple `Forwarded` directives rather than as a single quoted `for` value.

In 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.

## Details

`Rack::Utils.forwarded_values` processes the header using logic equivalent to:

```ruby
forwarded_header.split(';').each_with_object({}) do |field, values|
  field.split(',').each do |pair|
    pair = pair.split('=').map(&:strip).join('=')
    return nil unless pair =~ /\A(by|for|host|proto)="?([^"]+)"?\Z/i
    (values[$1.downcase.to_sym] ||= []) << $2
  end
end
```

The 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.

As a result, a header value such as:

```http
Forwarded: for="127.0.0.1;host=evil.com;proto=https"
```

is not treated as a single `for` value. Instead, Rack may interpret it as if the client had supplied separate `for`, `host`, and `proto` directives.

This 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.

## Impact

Applications that rely on `Forwarded` to derive request metadata may observe attacker-controlled values for `host`, `proto`, `for`, or related URL components.

In 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.

The 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.

## Mitigation

* Update to a patched version of Rack that parses `Forwarded` quoted-string values before splitting on parameter delimiters.
* Avoid trusting client-supplied `Forwarded` headers unless they are normalized or regenerated by a trusted reverse proxy.
* Prefer stripping inbound `Forwarded` headers at the edge and reconstructing them from trusted proxy metadata.
* Avoid using `req.host`, `req.scheme`, `req.base_url`, or `req.url` for security-sensitive operations unless the forwar