Skip to content

IP netmask whitelist bypass via spoofable X-Forwarded-For header #76

Description

@MiMoHo

Summary

remote_addr() returns the value of the client-supplied X-Forwarded-For header whenever it is present, and this value is used for the ifpl_netmask_whitelist IP check that decides whether persistent ("keep me logged in") sessions are allowed. Because X-Forwarded-For is fully attacker-controlled, a client can spoof it to satisfy (or evade) the netmask whitelist.

  • Type: Access-control decision based on a spoofable request header (CWE-290 / CWE-348)
  • Reviewed at commit: bde7b68 (v5.2.0, current master)
  • Severity: Medium — bypasses the IP restriction intended to confine persistent logins to trusted networks (only relevant when ifpl_netmask_whitelist is configured).

Root cause

remote_addr() trusts X-Forwarded-For unconditionally:

function remote_addr()
{
    if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) {
        return $_SERVER["HTTP_X_FORWARDED_FOR"];
    } else if (isset($_SERVER["REMOTE_ADDR"])) {
        return $_SERVER["REMOTE_ADDR"];
    }
    return "";
}

and the returned value drives the whitelist check in persistent_login.php:49-54:

$netmaskwl = $rcmail->config->get('ifpl_netmask_whitelist', array());
if (!empty($netmaskwl)) {
    $user_ip = $this->remote_addr();
    ...
    if ($this->ip_in_range($user_ip, $netmaskwl[$i])) { $found = true; }
}

Any client can send X-Forwarded-For: <an IP inside the whitelist> to appear to originate from the trusted range, regardless of their real address. (Even without a reverse proxy in front of Roundcube, HTTP_X_FORWARDED_FOR is set purely from the request.)

Recommended fix

Do not trust X-Forwarded-For unconditionally. Roundcube core already solves this with rcube_utils::remote_addr(), which only honors forwarding headers when the request comes from a configured trusted proxy (proxy_whitelist). The plugin should delegate to rcube_utils::remote_addr() instead of reimplementing an unconditional-trust version, so the whitelist check runs against the real client address (or a proxy-provided one only when the proxy is trusted).

Disclosure

The repository has no SECURITY.md and GitHub private vulnerability reporting is not enabled, so there is no private channel; reporting here so it can be fixed. Happy to open a PR. Found during a security review of Roundcube and commonly-used plugins.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions