Skip to content

IPv6 addresses cannot be blocklisted or auth-banned — no fail-closed behaviour #208

Description

@v1ktorrr0x

Bug

ipToInt returns -1 for any IPv6 address. The CIDR branch continues; the exact-match branch can't match an IPv4 entry. isBlocked returns false unconditionally for all IPv6 clients, regardless of what is configured in IP_BLOCKLIST.

Source

src/middleware/ip-blocklist.ts

43  function ipToInt(ip: string): number {
44    const parts = ip.split(".").map(Number);
45    if (parts.length !== 4 || parts.some(...)) return -1;  // IPv6 always hits this
46    ...
88  function isBlocked(clientIp: string): boolean {
95      if (clientInt === -1) continue;   // CIDR branch skips all IPv6
96      if (clientIp === entry.ip) return true;  // exact branch can't match IPv4 entry

WS mirror: src/routes/ws.ts:602 (isClientIpBlocked) → same function. Auth-ban keys: ws.ts:130-152.

Impact

The middleware does not fail-closed — an unmatchable IPv6 IP flows to next() (the 400 path at ip-blocklist.ts:140-160 only fires when IP is null, not when it's an IPv6 string).

An operator who adds an abuser's IPv4 address to the blocklist is silently bypassed the moment the abuser switches to IPv6. The same root cause lets IPv6 rotation bypass the WS auth-failure ban, which also keys on the parsed IP.

Fix

Either add full IPv6 CIDR matching to parseEntry/isBlocked (using a vetted IP-parsing library, consistent with the /64 key fix), or if IPv6 blocklisting is out of scope, fail-closed: when PARSED_BLOCKLIST is non-empty and the client IP is IPv6, return a 403 rather than next(). Document the choice inline.

Note: the existing >>> vs === operator precedence at line 96 is correct — do not change it.

Verification

With IP_BLOCKLIST=<some-ipv4> set, connect from an IPv6 address → today: allowed. After fix: either matched (with IPv6 rules) or 403 (fail-closed).

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