fix(wolf-rbac): use trusted client IP source for access_check#13329
Merged
shreemaan-abhishek merged 3 commits intoMay 11, 2026
Merged
Conversation
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.
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.
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.
5 tasks
membphis
approved these changes
May 11, 2026
nic-6443
approved these changes
May 11, 2026
AlinsRan
approved these changes
May 11, 2026
shreemaan-abhishek
added a commit
that referenced
this pull request
May 13, 2026
* 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. * 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. * docs(chaitin-waf): clarify how real_client_ip selects the client IP Describe the two `config.real_client_ip` modes in terms of the value the plugin sends to the WAF service: APISIX's resolved client IP (true) versus the IP of the directly connected peer (false). The previous wording referenced only `X-Forwarded-For`, which no longer matches the resolution path.
wistefan
pushed a commit
to wistefan/apisix
that referenced
this pull request
Jun 16, 2026
…#13329) * fix(wolf-rbac): use trusted client IP source for access_check 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. * 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. * 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.
wistefan
pushed a commit
to wistefan/apisix
that referenced
this pull request
Jun 16, 2026
…e#13339) * 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 apache#13329. * 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. * docs(chaitin-waf): clarify how real_client_ip selects the client IP Describe the two `config.real_client_ip` modes in terms of the value the plugin sends to the WAF service: APISIX's resolved client IP (true) versus the IP of the directly connected peer (false). The previous wording referenced only `X-Forwarded-For`, which no longer matches the resolution path.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
The wolf-rbac plugin populates the
clientIPparameter sent to wolf-server's/wolf/rbac/access_checkendpoint by readingctx.var.http_x_real_ip, the rawX-Real-IPrequest header. This bypasses nginx'sreal_ipmodule: even though APISIX configuresreal_ip_from = { "127.0.0.1", "unix:" }by default — meaning nginx correctly rejectsX-Real-IPfrom untrusted sources when computing$remote_addr— the plugin reads the original header directly, so any external client can supply an arbitraryclientIPvalue.This change replaces the raw-header read with
core.request.get_remote_client_ip(ctx), which returns$remote_addrafterreal_ipprocessing. The new behavior is:real_ip_from): forwards the real client IP from the trusted header — same behavior the previous code intended.Which issue(s) this PR fixes:
Fixes #
Checklist