---
id: "GHSA-2gff-2mmg-m73p"
page: "https://infrastack.ai/live/GHSA-2gff-2mmg-m73p"
kind: "vulnerability"
aliases: ["GHSA-2gff-2mmg-m73p"]
title: "Possible IP spoofing in Action Dispatch RemoteIp"
severity: "high"
cvss: 7.4
epss: null
exploited: false
status: "open"
category: "package"
products: [{"name": "actionpack", "fixed": ["8.1.4.1"], "affected": ">= 8.1, < 8.1.4.1", "ecosystem": "rubygems"}]
ecosystems: ["rubygems"]
tags: ["actionpack", "cwe-348", "package", "rails", "rate-limiting", "ruby", "self-hosted"]
not_affected_if: ["default-proxy-strips-forwarded", "not-using-remote-ip", "rack-2"]
published_at: "2026-11-04T03:01:54+00:00"
first_seen_at: "2026-11-09T22:53:29+00:00"
updated_at: "2026-11-09T22:54:29+00:00"
sources: [{"source": "ghsa-repo", "url": "https://github.com/rails/rails/security/advisories/GHSA-2gff-2mmg-m73p", "first_seen_at": "2026-11-09T22:53:29+00:00"}]
exploit_sources: []
---

# Possible IP spoofing in Action Dispatch RemoteIp

Link for people: https://infrastack.ai/live/GHSA-2gff-2mmg-m73p (this .md is for agents)

Rails 8.1.0 through 8.1.4 reads the client IP from the Forwarded header ahead of X-Forwarded-For when Rack 3 is in use. An unauthenticated attacker who can send a Forwarded header through a proxy that passes it on can set request.remote_ip to any address, which can bypass IP-based access control and rate limits and falsify audit logs.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- rubygems:actionpack affected >= 8.1, < 8.1.4.1 fixed 8.1.4.1

## How to check

- Check the Rails version in `Gemfile.lock` for `actionpack` between `8.1.0` and `8.1.4`, and confirm Rack 3 is in use (`rack` 3.x in `Gemfile.lock`).
- Check whether the reverse proxy in front of the app removes or overwrites a client-supplied `Forwarded` header.
- Check whether the app relies on `request.remote_ip` for access control, rate limiting, or auditing.

## Fix

- `actionpack` `8.1.4.1`
- Configure reverse proxies to remove or overwrite any client-supplied `Forwarded` header.
- Workaround for proxies that set `X-Forwarded-For`: set `Rack::Request.forwarded_priority = [:x_forwarded]` in an initializer (Rack 3.0.0 and later; this also makes Rack ignore `Forwarded` for scheme, host and port).

## Timeline

- 2026-11-09T22:53:29+00:00 ghsa-repo https://github.com/rails/rails/security/advisories/GHSA-2gff-2mmg-m73p

## Documents

- [advisory] Maintainer's advisory: github.com https://github.com/rails/rails/security/advisories/GHSA-2gff-2mmg-m73p

## From the sources

### Impact
Since Rails 8.1.0, `ActionDispatch::RemoteIp` derives `request.remote_ip` from `Rack::Request#forwarded_for`, which under Rack 3 reads the RFC 7239 `Forwarded` header in preference to `X-Forwarded-For`. When a reverse proxy appends the client address to `X-Forwarded-For` but passes a client-supplied `Forwarded` header through unchanged, `request.remote_ip` returns an address chosen by the client, and the IP spoofing check does not raise, because it compares only `Client-Ip` with the forwarded addresses. An unauthenticated attacker could therefore spoof `request.remote_ip`, possibly bypassing IP-based access controls and rate limits keyed on the client address (including the default `by:` of `rate_limit`), and falsifying the client address in logs.

### Details
The 8.1.0 change ([2d084af8](https://github.com/rails/rails/commit/2d084af8444a7b6b868c7cbb256172007871e78d)) switched `ActionDispatch::RemoteIp` from reading `X-Forwarded-For` directly to Rack's `forwarded_for`, in order to reuse Rack's port handling. Rails continues to honor `Forwarded`, the standard header.

In the fixed releases, when `config.action_dispatch.ip_spoofing_check` is enabled (the default), `ActionDispatch::RemoteIp` also compares the first untrusted client address in `Forwarded` with the first untrusted client address in `X-Forwarded-For`, as exact strings, and raises `ActionDispatch::RemoteIp::IpSpoofAttackError` when both headers are present and the addresses differ. Deployments whose proxies report the client address inconsistently between the two headers will receive this error after upgrading. See the `actionpack` CHANGELOG.

### Affected applications
An application is affected if it meets all of these requirements:
- Runs Rails 8.1.0 through 8.1.4 with Rack 3. Under Rack 2.2, `forwarded_for` reads only `X-Forwarded-For`.
- Is served behind a proxy that does not remove or overwrite a client-supplied `Forwarded` header.
- Relies on `request.remote_ip` for access control, rate limiting, or auditing.

The fix detects a spoofed `Forwarded` header only when the proxy also sets `X-Forwarded-For`. An application whose proxy passes a client-supplied `Forwarded` header through and sets no `X-Forwarded-For` remains exposed after upgrading, and should configure the proxy to remove or overwrite `Forwarded`, or apply the workaround below.

### Mitigation
- Upgrade to a fixed version of `actionpack`.
- Configure reverse proxies to remove or overwrite any client-supplied `Forwarded` header.

### Workarounds
Applications whose proxies set `X-Forwarded-For` can make Rack ignore the `Forwarded` header, restoring the client address resolution of Rails 8.0, by setting `Rack::Request.forwarded_priority = [:x_forwarded]` in an initializer. This setting is available in Rack 3.0.0 and later, and it also causes Rack to ignore `Forwarded` when determining the request scheme, host, and port.

### Releases
The fixed releases are available at the normal locations.

Patches for those who cannot upgrade at once:
- 8.1: https://github.com/rails/rails/commit/2a01a5ac521184419d9a92fa2c25e102e68cd227.patch

### Versions affected
- actionpack >= 8.1, < 8.1.4.1

### Credit
This issue was responsibly reported by HackerOne researcher [luryus](https://hackerone.com/luryus).

---

_Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai_
