From a3583cb54ed0dd93861c7b96cf427e1ad8451b31 Mon Sep 17 00:00:00 2001 From: Abhishek Choudhary Date: Tue, 5 May 2026 15:53:49 +0800 Subject: [PATCH 1/3] fix(wolf-rbac): use trusted client IP source for access_check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The plugin previously read the raw `X-Real-IP` request header to populate the `clientIP` parameter sent to wolf-server, falling back to `core.request.get_ip` only if the header was absent. Reading the raw header bypasses nginx's `real_ip` module, so any client could supply an arbitrary value regardless of the configured `real_ip_from` trusted proxy chain. Switch to `core.request.get_remote_client_ip`, which returns `$remote_addr` after `real_ip` processing — both correct when APISIX is behind a trusted proxy and unspoofable from untrusted sources. --- apisix/plugins/wolf-rbac.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apisix/plugins/wolf-rbac.lua b/apisix/plugins/wolf-rbac.lua index 9d54d3758830..8ead04fb5afd 100644 --- a/apisix/plugins/wolf-rbac.lua +++ b/apisix/plugins/wolf-rbac.lua @@ -241,7 +241,7 @@ end function _M.rewrite(conf, ctx) local url = ctx.var.uri local action = ctx.var.request_method - local client_ip = ctx.var.http_x_real_ip or core.request.get_ip(ctx) + local client_ip = core.request.get_remote_client_ip(ctx) local perm_item = {action = action, url = url, clientIP = client_ip} core.log.info("hit wolf-rbac rewrite") From 246846b44840573d8679f121ecbdc95a5e996d5d Mon Sep 17 00:00:00 2001 From: Abhishek Choudhary Date: Tue, 5 May 2026 16:48:52 +0800 Subject: [PATCH 2/3] test(wolf-rbac): assert clientIP respects trusted-proxy chain Add regression coverage for the IP source change in wolf-rbac: - Mock wolf-server now logs the `clientIP` query arg it receives, so tests can assert what the plugin forwarded. - TEST 41: when the source is in `set_real_ip_from`, an `X-Real-IP` header is honored and forwarded to wolf-server. - TEST 42: when the source is NOT in `set_real_ip_from`, a spoofed `X-Real-IP` is ignored and the actual peer address is forwarded. --- t/lib/server.lua | 1 + t/plugin/wolf-rbac.t | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/t/lib/server.lua b/t/lib/server.lua index 97908e214e72..48ca158486c8 100644 --- a/t/lib/server.lua +++ b/t/lib/server.lua @@ -318,6 +318,7 @@ function _M.wolf_rbac_access_check() local args = ngx.req.get_uri_args() local resName = args.resName + ngx.log(ngx.WARN, "wolf_rbac_access_check clientIP: ", args.clientIP or "") if resName == '/hello' or resName == '/wolf/rbac/custom/headers' then ngx.say(json_encode({ok=true, data={ userInfo={nickname="administrator", diff --git a/t/plugin/wolf-rbac.t b/t/plugin/wolf-rbac.t index 86cf0bf45cfd..b7bf5f8998b0 100644 --- a/t/plugin/wolf-rbac.t +++ b/t/plugin/wolf-rbac.t @@ -860,3 +860,33 @@ ssl_verify: true qr/ssl_verify/ --- no_error_log [error] + + + +=== TEST 41: clientIP forwarded from trusted X-Real-IP source +--- http_config +real_ip_header X-Real-IP; +set_real_ip_from 127.0.0.1; +--- request +GET /hello +--- more_headers +Authorization: V1#wolf-rbac-app#wolf-rbac-token +X-Real-IP: 192.0.2.10 +--- error_log +wolf_rbac_access_check clientIP: 192.0.2.10 + + + +=== TEST 42: spoofed X-Real-IP from untrusted source is ignored +--- http_config +real_ip_header X-Real-IP; +set_real_ip_from 192.0.2.1; +--- request +GET /hello +--- more_headers +Authorization: V1#wolf-rbac-app#wolf-rbac-token +X-Real-IP: 192.0.2.10 +--- error_log +wolf_rbac_access_check clientIP: 127.0.0.1 +--- no_error_log +wolf_rbac_access_check clientIP: 192.0.2.10 From 4a2f37ac9faf87a7b591d565f0b3490c6c6664ed Mon Sep 17 00:00:00 2001 From: Abhishek Choudhary Date: Thu, 7 May 2026 16:13:30 +0800 Subject: [PATCH 3/3] fix(wolf-rbac): also use trusted client IP in change_pwd log path The same plugin still called `core.request.get_ip` for the missing-token log line in `get_wolf_token`. It was non-spoofable but inaccurate behind a trusted proxy, so two paths in one file resolved client IP differently. Switch to `core.request.get_remote_client_ip` here as well so the whole plugin uses one consistent source. --- apisix/plugins/wolf-rbac.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apisix/plugins/wolf-rbac.lua b/apisix/plugins/wolf-rbac.lua index 8ead04fb5afd..e276071863e7 100644 --- a/apisix/plugins/wolf-rbac.lua +++ b/apisix/plugins/wolf-rbac.lua @@ -422,7 +422,7 @@ local function get_wolf_token(ctx) if rbac_token == nil then local url = ctx.var.uri local action = ctx.var.request_method - local client_ip = core.request.get_ip(ctx) + local client_ip = core.request.get_remote_client_ip(ctx) local perm_item = {action = action, url = url, clientIP = client_ip} core.log.info("no permission to access ", core.json.delay_encode(perm_item), ", need login!")