Skip to content

[Bug] Cloudflare: country flag uses proxy IP instead of visitor's real IP #150

@parhumm

Description

@parhumm

Validation Result: Confirmed Bug

Verdict: VALID_BUG | Confidence: HIGH | Severity: Medium

Related: wp.org support thread — Behind Proxy

Summary

Confirmed: behind Cloudflare, the country flag can show the Cloudflare data center's country instead of the visitor's real country. Two root causes identified in the codebase.

Root Cause

Fault Location 1: src/Tracker/Utils.php:133
Mechanism: The IP detection function does not check HTTP_CF_CONNECTING_IP (Cloudflare's primary header for the real client IP). Only standard proxy headers like HTTP_X_FORWARDED_FOR are checked.

Fault Location 2: src/Tracker/Processor.php:241
Mechanism: The tracking pipeline hardcodes provider selection as maxmind or dbip, ignoring the geolocation_provider admin setting. The Cloudflare geolocation provider (which reads HTTP_CF_IPCOUNTRY directly from Cloudflare headers) exists but is never invoked during tracking.

Causal Chain:

  1. Visitor behind Cloudflare → REMOTE_ADDR is CF edge IP
  2. getRemoteIp() may not detect real IP (missing CF-Connecting-IP header)
  3. Even if detected, geolocation IP priority logic can be inverted when server restores real IP via mod_remoteip
  4. Cloudflare geolocation provider (which bypasses IP lookup entirely using CF headers) is unreachable in tracking pipeline
  5. Result: geolocation resolves to CF data center country for all visitors

Workaround (Available Now)

Use the slimstat_filter_ip_address filter to prioritize HTTP_CF_CONNECTING_IP:

add_filter('slimstat_filter_ip_address', function($ipArray) {
    if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) {
        $cfIp = filter_var($_SERVER['HTTP_CF_CONNECTING_IP'], FILTER_VALIDATE_IP);
        if ($cfIp) {
            $ipArray[1] = $ipArray[0]; // Move REMOTE_ADDR to other_ip
            $ipArray[0] = $cfIp;       // Set real IP as primary
        }
    }
    return $ipArray;
});

Code References

File Lines Description
src/Tracker/Utils.php 125-148 IP detection — missing CF-Connecting-IP
src/Tracker/Processor.php 69 Geolocation IP selection logic
src/Tracker/Processor.php 241 Hardcoded provider selection (ignores CF)
src/Services/Geolocation/Provider/CloudflareGeolocationProvider.php 1-92 Cloudflare provider (dead code in tracker)
admin/config/index.php 281-290 Admin UI offers Cloudflare option

Validated via qa-issue-validate skill (jaan.to plugin)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions