From e2778575674d24d8d7c55615953929939d96e2cd Mon Sep 17 00:00:00 2001 From: Abhishek Choudhary Date: Thu, 7 May 2026 19:23:46 +0800 Subject: [PATCH 1/2] fix(chaitin-waf): use trusted client IP source for WAF backend The plugin populated `client_ip` sent to the Chaitin WAF backend by reading `ctx.var.http_x_forwarded_for` directly when `real_client_ip` is enabled, bypassing nginx's `real_ip` module. Any external client could supply an arbitrary `X-Forwarded-For` header and have it forwarded to the WAF unchecked. Replace the raw-header read with `core.request.get_remote_client_ip` (realip-aware) when `real_client_ip = true`, and `core.request.get_ip` (direct TCP peer) when false. This applies the same fix shape used for wolf-rbac in #13329. --- apisix/plugins/chaitin-waf.lua | 5 +- t/plugin/chaitin-waf.t | 93 ++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 2 deletions(-) diff --git a/apisix/plugins/chaitin-waf.lua b/apisix/plugins/chaitin-waf.lua index 6c82c4a70f6b..d5a57173cd69 100644 --- a/apisix/plugins/chaitin-waf.lua +++ b/apisix/plugins/chaitin-waf.lua @@ -343,10 +343,11 @@ local function do_access(conf, ctx) end if t.real_client_ip then - t.client_ip = ctx.var.http_x_forwarded_for or ctx.var.remote_addr + t.client_ip = core.request.get_remote_client_ip(ctx) else - t.client_ip = ctx.var.remote_addr + t.client_ip = core.request.get_ip(ctx) end + core.log.info("chaitin-waf client_ip: ", t.client_ip) local start_time = ngx_now() * 1000 local ok, err, result = t1k.do_access(t, false) diff --git a/t/plugin/chaitin-waf.t b/t/plugin/chaitin-waf.t index ebff234ac905..dda3df08371c 100644 --- a/t/plugin/chaitin-waf.t +++ b/t/plugin/chaitin-waf.t @@ -405,3 +405,96 @@ hello world X-APISIX-CHAITIN-WAF: yes X-APISIX-CHAITIN-WAF-ACTION: pass X-APISIX-CHAITIN-WAF-STATUS: 200 + + + +=== TEST 12: real_client_ip = true prepare +--- config + location /do { + content_by_lua_block { + local t = require("lib.test_admin").test + + local code, body = t('/apisix/admin/plugin_metadata/chaitin-waf', + ngx.HTTP_PUT, + [[{ + "nodes": [ + { + "host": "127.0.0.1", + "port": 8088 + } + ] + }]] + ) + if code >= 300 then + ngx.status = code + return ngx.print(body) + end + + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "methods": ["GET"], + "plugins": { + "chaitin-waf": { + "match": [ + { + "vars": [ + ["http_trigger", "==", "true"] + ] + } + ], + "config": { + "real_client_ip": true + } + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/*" + }]] + ) + if code >= 300 then + ngx.status = code + return ngx.print(body) + end + ngx.say("passed") + } + } +--- response_body +passed + + + +=== TEST 13: client_ip from trusted X-Forwarded-For source +--- http_config +real_ip_header X-Forwarded-For; +set_real_ip_from 127.0.0.1; +--- request +GET /hello +--- more_headers +X-Forwarded-For: 192.0.2.10 +trigger: true +--- error_code: 200 +--- error_log +chaitin-waf client_ip: 192.0.2.10 + + + +=== TEST 14: spoofed X-Forwarded-For from untrusted source is ignored +--- http_config +real_ip_header X-Forwarded-For; +set_real_ip_from 192.0.2.1; +--- request +GET /hello +--- more_headers +X-Forwarded-For: 192.0.2.10 +trigger: true +--- error_code: 200 +--- error_log +chaitin-waf client_ip: 127.0.0.1 +--- no_error_log +chaitin-waf client_ip: 192.0.2.10 From 709957238fe3bc71c4459e03cad025e970411d41 Mon Sep 17 00:00:00 2001 From: Abhishek Choudhary Date: Fri, 8 May 2026 11:17:49 +0800 Subject: [PATCH 2/2] fix(chaitin-waf): preserve real_client_ip=false in get_conf merge `get_conf` merged `real_client_ip` with `or`, which silently fell back to the default `true` whenever the user explicitly set `false`, making the toggle ineffective. Replace with an explicit nil check so both `true` and `false` overrides are honored. Also tighten the existing `real_client_ip = false` test to assert the chosen `client_ip` (not just the response), and add a regression case that verifies the `false` branch wins over `set_real_ip_from`-trusted `X-Forwarded-For` rewrites. --- apisix/plugins/chaitin-waf.lua | 8 ++++++-- t/plugin/chaitin-waf.t | 27 ++++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/apisix/plugins/chaitin-waf.lua b/apisix/plugins/chaitin-waf.lua index d5a57173cd69..ed364bb9ab42 100644 --- a/apisix/plugins/chaitin-waf.lua +++ b/apisix/plugins/chaitin-waf.lua @@ -280,7 +280,9 @@ local function get_conf(conf, metadata) t.req_body_size = metadata.config.req_body_size t.keepalive_size = metadata.config.keepalive_size t.keepalive_timeout = metadata.config.keepalive_timeout - t.real_client_ip = metadata.config.real_client_ip or t.real_client_ip + if metadata.config.real_client_ip ~= nil then + t.real_client_ip = metadata.config.real_client_ip + end end if conf.config then @@ -290,7 +292,9 @@ local function get_conf(conf, metadata) t.req_body_size = conf.config.req_body_size t.keepalive_size = conf.config.keepalive_size t.keepalive_timeout = conf.config.keepalive_timeout - t.real_client_ip = conf.config.real_client_ip or t.real_client_ip + if conf.config.real_client_ip ~= nil then + t.real_client_ip = conf.config.real_client_ip + end end t.mode = conf.mode or metadata.mode or t.mode diff --git a/t/plugin/chaitin-waf.t b/t/plugin/chaitin-waf.t index dda3df08371c..df7f7ed366f5 100644 --- a/t/plugin/chaitin-waf.t +++ b/t/plugin/chaitin-waf.t @@ -405,10 +405,31 @@ hello world X-APISIX-CHAITIN-WAF: yes X-APISIX-CHAITIN-WAF-ACTION: pass X-APISIX-CHAITIN-WAF-STATUS: 200 +--- error_log +chaitin-waf client_ip: 127.0.0.1 +--- no_error_log +chaitin-waf client_ip: 1.2.3.4 + + + +=== TEST 12: real_client_ip = false ignores trusted X-Forwarded-For +--- http_config +real_ip_header X-Forwarded-For; +set_real_ip_from 127.0.0.1; +--- request +GET /hello +--- more_headers +X-Forwarded-For: 192.0.2.10 +trigger: true +--- error_code: 200 +--- error_log +chaitin-waf client_ip: 127.0.0.1 +--- no_error_log +chaitin-waf client_ip: 192.0.2.10 -=== TEST 12: real_client_ip = true prepare +=== TEST 13: real_client_ip = true prepare --- config location /do { content_by_lua_block { @@ -469,7 +490,7 @@ passed -=== TEST 13: client_ip from trusted X-Forwarded-For source +=== TEST 14: client_ip from trusted X-Forwarded-For source --- http_config real_ip_header X-Forwarded-For; set_real_ip_from 127.0.0.1; @@ -484,7 +505,7 @@ chaitin-waf client_ip: 192.0.2.10 -=== TEST 14: spoofed X-Forwarded-For from untrusted source is ignored +=== TEST 15: spoofed X-Forwarded-For from untrusted source is ignored --- http_config real_ip_header X-Forwarded-For; set_real_ip_from 192.0.2.1;