CVE-2009-3287
Description
Thin web server before 1.2.4 trusts X-Forwarded-For header, enabling remote attackers to spoof client IP addresses.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Thin web server before 1.2.4 trusts X-Forwarded-For header, enabling remote attackers to spoof client IP addresses.
Vulnerability
In Thin web server versions before 1.2.4, the lib/thin/connection.rb file relies on the X-Forwarded-For HTTP header to determine the client's IP address. This is used in the Connection#remote_address method. The code path is reachable for any request that includes the X-Forwarded-For header [1][2].
Exploitation
An attacker can send a crafted HTTP request with a modified X-Forwarded-For header to spoof the client IP address. No authentication or special network position is required; the attacker only needs to make a request to the Thin server [1][3].
Impact
By spoofing the IP address, an attacker can hide their true identity and location. This can be used to bypass IP-based access controls, logging, or rate limiting. The vulnerability does not directly lead to code execution or data disclosure, but enables further malicious activities to be attributed to a false source [1][3].
Mitigation
The fix was released in Thin version 1.2.4. The commit [2] shows that the remote_address method was changed to use the socket address instead of the forwarded-for header. Users should upgrade to Thin 1.2.4 or later. No workarounds are documented for earlier versions [2][4].
AI Insight generated on May 23, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
thinRubyGems | < 1.2.4 | 1.2.4 |
Affected products
22cpe:2.3:a:macournoyer:thin:*:*:*:*:*:*:*:*+ 20 more
- cpe:2.3:a:macournoyer:thin:*:*:*:*:*:*:*:*range: <=1.2.2
- cpe:2.3:a:macournoyer:thin:0.4.0:*:*:*:*:*:*:*
- cpe:2.3:a:macournoyer:thin:0.4.1:*:*:*:*:*:*:*
- cpe:2.3:a:macournoyer:thin:0.5.0:*:*:*:*:*:*:*
- cpe:2.3:a:macournoyer:thin:0.5.1:*:*:*:*:*:*:*
- cpe:2.3:a:macournoyer:thin:0.5.2:*:*:*:*:*:*:*
- cpe:2.3:a:macournoyer:thin:0.5.3:*:*:*:*:*:*:*
- cpe:2.3:a:macournoyer:thin:0.5.4:*:*:*:*:*:*:*
- cpe:2.3:a:macournoyer:thin:0.6.0:*:*:*:*:*:*:*
- cpe:2.3:a:macournoyer:thin:0.6.3:*:*:*:*:*:*:*
- cpe:2.3:a:macournoyer:thin:0.6.4:*:*:*:*:*:*:*
- cpe:2.3:a:macournoyer:thin:0.7.0:*:*:*:*:*:*:*
- cpe:2.3:a:macournoyer:thin:0.7.1:*:*:*:*:*:*:*
- cpe:2.3:a:macournoyer:thin:0.8.0:*:*:*:*:*:*:*
- cpe:2.3:a:macournoyer:thin:0.8.1:*:*:*:*:*:*:*
- cpe:2.3:a:macournoyer:thin:0.8.2:*:*:*:*:*:*:*
- cpe:2.3:a:macournoyer:thin:1.0.0:*:*:*:*:*:*:*
- cpe:2.3:a:macournoyer:thin:1.1.0:*:*:*:*:*:*:*
- cpe:2.3:a:macournoyer:thin:1.1.1:*:*:*:*:*:*:*
- cpe:2.3:a:macournoyer:thin:1.2.0:*:*:*:*:*:*:*
- cpe:2.3:a:macournoyer:thin:1.2.1:*:*:*:*:*:*:*
Patches
17bd027914c5fFix Remote address spoofing vulnerability in Connection#remote_address [Alexey Borzenkov]
5 files changed · +7 −10
CHANGELOG+1 −0 modified@@ -1,4 +1,5 @@ == 1.2.3 + * Fix Remote address spoofing vulnerability in Connection#remote_address [Alexey Borzenkov] * Fix uninitialized constant ActionController::Dispatcher error with Rails 1.2.3 [Chris Anderton] [#103 state:resolved] == 1.2.2 I Find Your Lack of Sauce Disturbing release
lib/thin/connection.rb+1 −1 modified@@ -180,7 +180,7 @@ def threaded? # IP Address of the remote client. def remote_address - @request.forwarded_for || socket_address + socket_address rescue Exception log_error nil
lib/thin/request.rb+0 −5 modified@@ -21,7 +21,6 @@ class Request HTTP_VERSION = 'HTTP_VERSION'.freeze HTTP_1_0 = 'HTTP/1.0'.freeze REMOTE_ADDR = 'REMOTE_ADDR'.freeze - FORWARDED_FOR = 'HTTP_X_FORWARDED_FOR'.freeze CONTENT_LENGTH = 'CONTENT_LENGTH'.freeze CONNECTION = 'HTTP_CONNECTION'.freeze KEEP_ALIVE_REGEXP = /\bkeep-alive\b/i.freeze @@ -123,10 +122,6 @@ def remote_address=(address) @env[REMOTE_ADDR] = address end - def forwarded_for - @env[FORWARDED_FOR] - end - def threaded=(value) @env[RACK_MULTITHREAD] = value end
lib/thin/version.rb+2 −2 modified@@ -6,11 +6,11 @@ class PlatformNotSupported < RuntimeError; end module VERSION #:nodoc: MAJOR = 1 MINOR = 2 - TINY = 2 + TINY = 3 STRING = [MAJOR, MINOR, TINY].join('.') - CODENAME = "I Find Your Lack of Sauce Disturbing".freeze + CODENAME = "Astroboy".freeze RACK = [1, 0].freeze # Rack protocol version end
spec/connection_spec.rb+3 −2 modified@@ -40,9 +40,10 @@ @connection.process end - it "should return HTTP_X_FORWARDED_FOR as remote_address" do + it "should not return HTTP_X_FORWARDED_FOR as remote_address" do @connection.request.env['HTTP_X_FORWARDED_FOR'] = '1.2.3.4' - @connection.remote_address.should == '1.2.3.4' + @connection.stub!(:socket_address).and_return("127.0.0.1") + @connection.remote_address.should == "127.0.0.1" end it "should return nil on error retreiving remote_address" do
Vulnerability mechanics
Root cause
"The `remote_address` method in `Connection` trusts the `X-Forwarded-For` HTTP header over the actual socket address, allowing client IP spoofing."
Attack vector
An attacker sends an HTTP request to the Thin server with a crafted `X-Forwarded-For` header containing an arbitrary IP address. The vulnerable `Connection#remote_address` method [patch_id=21] returns the value of `HTTP_X_FORWARDED_FOR` (via `Request#forwarded_for`) instead of the actual TCP socket address. This allows the attacker to masquerade as any IP address, bypassing IP-based access controls, rate limiting, or audit logging. No authentication or special network position is required; the attacker only needs to be able to send HTTP requests to the server.
Affected code
The vulnerability is in `lib/thin/connection.rb` at the `remote_address` method, which previously returned `@request.forwarded_for || socket_address`. The `forwarded_for` method in `lib/thin/request.rb` simply read `HTTP_X_FORWARDED_FOR` from the environment without any validation. The patch removes both the `forwarded_for` method and the fallback logic.
What the fix does
The patch removes the `forwarded_for` method from `Request` [patch_id=21] and changes `Connection#remote_address` to always call `socket_address` instead of falling back to the `X-Forwarded-For` header. The spec test is updated to assert that even when `HTTP_X_FORWARDED_FOR` is set, the returned address is the socket address (127.0.0.1). This closes the spoofing vector by no longer accepting client-supplied header values as the authoritative remote address.
Preconditions
- networkAttacker must be able to send HTTP requests to the Thin server.
- inputAttacker must include a crafted X-Forwarded-For header in the HTTP request.
Generated on May 19, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/macournoyer/thin/commit/7bd027914c5ffd36bb408ef47dc749de3b6e063anvdPatchWEB
- github.com/advisories/GHSA-j24p-r6wx-r79wghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2009-3287ghsaADVISORY
- github.com/macournoyer/thin/blob/master/CHANGELOGnvdWEB
- www.openwall.com/lists/oss-security/2009/09/12/1nvdWEB
- github.com/rubysec/ruby-advisory-db/blob/master/gems/thin/CVE-2009-3287.ymlghsaWEB
News mentions
0No linked articles in our index yet.