GitHub Advisoryadvisory · npm

GHSA-4xrf-jv44-h6hh ip-address: a CIDR suffix on the parsed address suppresses special-use classification and can bypass SSRF and trust-boundary checks

MEDIUM Published 2026-08-03 Modified 2026-08-03 Official page ↗
Aliases
CVE-2026-69198
Ecosystem
npm
Packages
ip-address
Severity
Moderate
CVSS vector
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:H/SI:N/SA:N
Weaknesses
CWE-20, CWE-918
Reviewed
2026-08-03

Affected packages

• npm ip-address: >= 10.1.1, < 10.2.2 → fixed in 10.2.2

Description

Summary Every special-use classification method is built on `isInSubnet`, which short-circuits to `false` whenever the address's own subnet mask is *shorter* than the reference range's mask. That mask comes verbatim from the CIDR suffix on the parsed input, so appending a suffix such as `/0` suppresses classification entirely: `isLoopback()`, `isPrivate()`, `isLinkLocal()`, `isCGNAT()`, `isMulticast()`, `isUnspecified()`, `isBroadcast()`, `isULA()`, and `getType()` all report an internal address as unremarkable, while `correctForm()` and `address` still return the real internal target. An application that builds a network trust-boundary decision on these checks (for example a filter intended to block Server-Side Request Forgery, or SSRF) may therefore treat an internal target as external and allow the request. SSRF is an attack in which a user-supplied address coaxes the server into making a request to an internal destination the user could not otherwise reach, such as a loopback service or a cloud metadata endpoint. Details `isInSubnet` in `src/common.ts` opens with a guard that compares the two prefix lengths: ```js export function isInSubnet(this, address) { if (this.subnetMask = 10.1.1, block as internal, false => allow outbound function isBlocked(host) { try { const a = new Address4(host); return a.isPrivate() || a.isLoopback() || a.isLinkLocal() || a.isCGNAT() || a.isMulticast() || a.isUnspecified() || a.isBroadcast(); } catch {} try { const a = new Address6(host); return a.isPrivate() || a.isLoopback() || a.isLinkLocal() || a.isULA() || a.isMulticast() || a.isUnspecified(); } catch {} return false; } for (const h of ['127.0.0.1', '10.0.0.1', '::1', '127.0.0.1/0', '10.0.0.5/7', '169.254.169.254/0', '::1/0', '::ffff:127.0.0.1/0', '64:ff9b::7f00:1/0']) { console.log(isBlocked(h) ? 'BLOCK ' : 'ALLOW ', h, '->', new (h.includes(':') ? Address6 : Address4)(h).correctForm()); } ``` On affected versions every suffixed internal target is allowed, and `correctForm()` shows the request would reach the real internal address: ``` BLOCK 127.0.0.1 -> 127.0.0.1 BLOCK 10.0.0.1 -> 10.0.0.1 BLOCK ::1 -> ::1 ALLOW 127.0.0.1/0 -> 127.0.0.1 ALLOW 10.0.0.5/7 -> 10.0.0.5 ALLOW 169.254.169.254/0 -> 169.254.169.254 ALLOW ::1/0 -> ::1 ALLOW ::ffff:127.0.0.1/0 -> ::ffff:7f00:1 ALLOW 64:ff9b::7f00:1/0 -> 64:ff9b::7f00:1 ``` The first three lines are blocked as expected; the same destinations with a CIDR suffix are allowed through. Remediation Upgrade to the patched release. In the fix, classification no longer consults the address's own prefix: a new `isHostInSubnet()` compares the address's host bits against the reference range only, and every classifier (`isLoopback`, `isPrivate`, `isLinkLocal`, `isCGNAT`, `isMulticast`, `isUnspecified`, `isBroadcast`, `isULA`, `isMapped4`, `isTeredo`, `is6to4`, `isDocumentation`, `getType`, and the IPv4-mapped/NAT64 normalization behind `embeddedIPv4`) uses it. `isInSubnet` keeps its subnet-containment semantics unchanged, including the guard that a wider network is not contained in a narrower one. After upgrading, `new Address4('127.0.0.1/0').isLoopback()` returns `true`. If you cannot upgrade immediately, strip the suffix before classifying by re-parsing `addressMinusSuffix`: ```js const parsed = new Address4(userInput); const host = new Address4(parsed.addressMinusSuffix); // classify this one ``` A note on SSRF defense These methods are address classifiers, not a complete SSRF defense. Regardless of this fix, a robust SSRF guard must resolve the hostname and validate the *resolved* IP against the socket it connects to, and account for DNS rebinding and redirects. Treat these checks as one layer, not the only one. Credit Reported by @hi-im-glitchless.

Related

Alias · CVE (1)

  • CVE-2026-69198 ip-address is a library for parsing and manipulating IPv4 and IPv6 addresses in JavaScript. vulnerability

Weakness · CWE (2)

  • CWE-20 Improper Input Validation weakness
  • CWE-918 Server-Side Request Forgery weakness

References