Skip to main content

ip-address EUVDEUVD-2026-52422

| CVE-2026-69198 MEDIUM
Improper Input Validation (CWE-20)
2026-08-03 https://github.com/beaugunderson/ip-address GHSA-4xrf-jv44-h6hh
6.9
CVSS 4.0 · Vendor: https://github.com/beaugunderson/ip-address
View

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain

  1. Recon
    Submit internal IP with CIDR suffix to application input field
  2. Delivery
    Application constructs ip-address object retaining /0 as subnetMask
  3. Exploit
    isInSubnet guard compares prefix lengths, short-circuits to false
  4. Install
    All classification methods return false for internal address
  5. C2
    SSRF trust-boundary check passes
  6. Execute
    Application server issues request to internal target
  7. Impact
    Attacker receives internal service response

Vulnerability Assessment

Weakness
CWE
OWASP Top 10:2025
A05:2025 - Injection
ASVS 5.0
V2 - Validation and Business Logic Input validation, allowlisting
Exploitation Conditions

Exploitation requires two co-occurring conditions: (1) the application accepts a bare IPv4 or IPv6 address string that may carry a CIDR suffix directly from user input - such as a webhook URL field, proxy destination field, or allow/deny list entry - without first extracting the hostname via URL parsing; and (2) the application uses ip-address version 10.1.1-10.2.1 classification methods (isLoopback, isPrivate, isLinkLocal, isCGNAT, isMulticast, isUnspecified, isBroadcast, isULA, getType) as its primary trust-boundary guard. Exploitation is NOT possible when the application pre-processes input through standard URL parsing (new URL(input).hostname strips the CIDR suffix before it reaches ip-address, leaving classification unaffected); when ip-address < 10.1.1 is in use (the classification API did not exist); or when no downstream network request is made to the classified address. The one partial exception is Address6.isLinkLocal() for native fe80::/10 addresses, which uses direct bit comparison and is not bypassed by a suffix - however, the IPv4-mapped path (::ffff:169.254.x.x/0) for the same method remains vulnerable. Any suffix shorter than the specific reference range being tested also triggers the bypass, not only /0 (e.g., 10.0.0.5/7 bypasses the 10.0.0.0/8 private range check).

Impact

The CVSS 4.0 vector (AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:H/SI:N/SA:N, score 6.9) accurately captures the split impact: the vulnerable system itself suffers only low confidentiality impact, but the subsequent system - internal services reachable via SSRF such as cloud metadata endpoints - suffers high confidentiality impact. The AT:P (Attack Requirements: Present) modifier is the critical risk limiter: the bypass only triggers when an application accepts bare address strings that may carry CIDR suffixes, rather than extracting hostnames from URLs before classification. Applications using the standard URL parsing pattern (new URL(input).hostname) are not affected, as the URL parser strips the CIDR suffix. The advisory explicitly confirms this reachability constraint. A POC is publicly documented in the GHSA advisory, lowering the bar for exploitation in affected applications. No EPSS data was provided, and no CISA KEV listing exists, so exploitation prevalence is not confirmed. The real-world risk is thus conditional: for applications matching the vulnerable pattern (webhook targets, proxy destinations, raw allow/deny fields), this is a high-impact SSRF bypass; for the majority using URL-based parsing, risk is negligible. No CVSS 3.1 vector was provided in the input data.

Exploit ScenarioDerived

An attacker submits 169.254.169.254/0 as a webhook target or proxy destination to an application that uses ip-address 10.1.1-10.2.1 classification methods as its SSRF guard. Because the /0 prefix is shorter than the link-local reference range /16, isLinkLocal() returns false without comparing address bits, and the guard passes; the application server then issues an HTTP request to the AWS or GCP instance metadata endpoint, potentially returning IAM credentials or other internal configuration data to the attacker. A working proof-of-concept demonstrating this bypass for multiple internal address classes is published in the GHSA advisory at https://github.com/beaugunderson/ip-address/security/advisories/GHSA-4xrf-jv44-h6hh.

This Month Plan within 30 days. Why: MEDIUM severity (CVSS 4.0-6.9).
Patch available 0.3% exploitation probability (EPSS)

Get an e-mail when this CVE is exploited, patched or re-scored. Free account.

Alert me

AnalysisAIv1 – Aug 03, 2026

SSRF classification bypass in the ip-address npm library (versions 10.1.1-10.2.1) allows network-accessible applications to be deceived into treating internal IP addresses as external. When a caller-supplied CIDR suffix such as /0 is retained during parsing, the isInSubnet() guard short-circuits before any bit comparison, causing every special-use classifier - isLoopback(), isPrivate(), isLinkLocal(), isCGNAT(), isMulticast(), and others - to return false for internal addresses, while correctForm() still resolves to the real internal target. A publicly available proof-of-concept is included in the GHSA advisory; no CISA KEV listing exists at time of analysis, so active exploitation is not confirmed.

RemediationAI

Upgrade the ip-address package to version 10.2.2 or later, available via npm (npm install ip-address@10.2.2) and confirmed by the release at https://github.com/beaugunderson/ip-address/releases/tag/v10.2.2 and the patch commit at https://github.com/beaugunderson/ip-address/commit/488fe9bc7c35363b4b090494fc38c266d217740d. After upgrading, new Address4('127.0.0.1/0').isLoopback() correctly returns true. If an immediate upgrade is not possible, strip the CIDR suffix before classifying by re-parsing through addressMinusSuffix: parse the raw user input with the constructor, then construct a second instance from parsed.addressMinusSuffix and classify that instance only. Trade-off: this workaround requires code changes at every call site where user input is classified. Additionally, as noted in the advisory, ip-address classifiers are not a complete SSRF defense regardless of this fix; a robust guard must also resolve hostnames, validate the resolved IP against the actual socket connection, and account for DNS rebinding and HTTP redirects.

Affected VersionsENISA

ip-address 10.1.1, < 10.2.2

Affected Packages

npm ip-address fix: 10.2.2

Source: OSV (Open Source Vulnerabilities)

Affects your stack

Affects 1 package in npm

Checking this CVE against your own stacks and servers is part of the Basic plan and up.

Technical ContextAI · show details

The ip-address library (pkg:npm/ip-address) is a TypeScript/JavaScript package for parsing and manipulating IPv4 and IPv6 addresses in Node.js environments. The defect resides in isInSubnet() in src/common.ts, which is the shared foundation for all special-use classification methods. The function opens with a prefix-length guard: if the input address's subnetMask is shorter than the reference range's mask, it returns false immediately, before comparing any address bits. This guard is semantically correct for subnet-containment checks but incorrect for host classification, where the caller-supplied prefix is irrelevant. Because the ip-address constructor retains the CIDR suffix verbatim in the subnetMask field, an input like 127.0.0.1/0 stores subnetMask=0, which is shorter than every special-use range prefix (loopback /8, link-local /16, CGNAT /10, ULA /7, multicast /4), causing all classifiers to return false for that address. The mask(n) helper already computes the first n bits of the full address independently of subnetMask, meaning the bit comparison itself is correct - the sole defect is the containment guard appearing in the classification code path. CWE-20 (Improper Input Validation) accurately describes the root cause: user-supplied CIDR notation is accepted and propagated into a context where it corrupts classification semantics. The fix in 10.2.2 introduces a new isHostInSubnet() helper that ignores the input address's own prefix length, and routes all classifiers through it.

Know when Node.js gets its next vulnerability

  • Watch products and get an email when something new is published
  • Check this CVE against your own stack and servers
  • Exploit and PoC references, threat intelligence from 22 sources

No credit card · 7-day full trial

Severity by source

Vendor (https://github.com/beaugunderson/ip-address) PRIMARY 6.9 MEDIUM
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
vuln.today AI 6.8 MEDIUM

AC:H because exploitation requires the uncommon application pattern of accepting raw CIDR-suffixed strings; S:C and C:H reflect SSRF reaching high-value internal systems with no integrity or availability impact.

3.1 AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N
4.0 AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:H/SI:N/SA:N
SUSE 4.8 MEDIUM
AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N
Red Hat 5.3 MEDIUM

Primary rating from Vendor (https://github.com/beaugunderson/ip-address).

CVSS VectorVendor: https://github.com/beaugunderson/ip-address

Attack Vector
Network
Attack Complexity
Low
Attack Requirements
Present
Privileges Required
None
User Interaction
None
Vulnerable system: Confidentiality
Low
Vulnerable system: Integrity
None
Vulnerable system: Availability
None
Subsequent system: Confidentiality
High
Subsequent system: Integrity
None
Subsequent system: Availability
None

Lifecycle Timeline

1
CVSS changed
Aug 03, 2026 - 20:22 NVD
6.9 (MEDIUM)

DescriptionCVE.org

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 < address.subnetMask) {
    return false;                                  // <-- reached before any bit comparison
  }

  if (this.mask(address.subnetMask) === address.mask()) {
    return true;
  }

  return false;
}

That guard is correct for the question isInSubnet is named for - whether one *network* is contained in another, where a /0 network genuinely is not inside a /8. It is wrong for classification, which asks a question about the address itself and must not depend on the prefix the caller happened to write. /0 is shorter than every reference prefix in the special-use tables (loopback /8, link-local /16, CGNAT /10, ULA /7, multicast /4), so for a classification call the bit comparison is never reached and the method returns false.

The underlying bit comparison is correct, and mask(n) already returns the first n bits of the full parsed address independently of subnetMask - the defect is solely that the containment guard sits in the classification path. Host bits are retained through parsing, so correctForm() still yields the real target and the address remains fully usable for connecting.

/0 is the universal case because it is shorter than every reference prefix, but any suffix shorter than the specific range being tested has the same effect: 10.0.0.5/7 defeats isPrivate() for 10.0.0.0/8.

Affected versions

>= 10.1.1, <= 10.2.1. The is* classification API was introduced for Address4 in 10.1.1 and extended to Address6 in 10.2.0; releases before 10.1.1 do not expose it and are not affected through this vector. The containment guard itself is much older, but isInSubnet alone is a subnet-containment predicate whose behavior here is correct.

This also defeats the fix released in 10.2.1 for GHSA-22jq-vg5j-6vgg: that release classifies IPv4-mapped and NAT64 addresses by their embedded IPv4 address, but the normalization is reached through isInSubnet, so ::ffff:127.0.0.1/0 reverts to being reported as non-internal.

Impact

Every classifier is affected on both Address4 and Address6. The sole exception is Address6.isLinkLocal() for *native* fe80::/10 addresses, which compares raw bits directly; its IPv4-mapped path is still affected.

AddressReported asActually points at
127.0.0.1/0not loopbackloopback (127.0.0.0/8)
10.0.0.1/0, 10.0.0.5/7not privateRFC 1918 10/8
172.16.5.5/0not privateRFC 1918 172.16/12
192.168.1.1/0not privateRFC 1918 192.168/16
169.254.169.254/0not link-locallink-local / cloud metadata (IMDS)
100.64.0.1/0not CGNATCGNAT 100.64/10
0.0.0.0/0, 255.255.255.255/0not unspecified / not broadcastunspecified / broadcast
::1/0not loopbackIPv6 loopback
fc00::1/0not ULA, not privateIPv6 ULA fc00::/7
ff02::1/0not multicastIPv6 multicast
::ffff:127.0.0.1/0not loopbackloopback, via IPv4-mapped
::ffff:169.254.169.254/0not link-localIMDS, via IPv4-mapped
64:ff9b::7f00:1/0not loopbackloopback, via NAT64

getType() returns Global unicast for all of the IPv6 cases above, and getScope() follows it.

Reachability

A CIDR suffix is not legal in a URL host, so this is not reachable through the most common SSRF shape. new URL('http://127.0.0.1/0') parses hostname as 127.0.0.1 and pathname as /0, and a guard that classifies the extracted hostname is unaffected. Exploitation requires an application that accepts a bare address string that may carry a suffix and passes it to the constructor before classifying - for example an allow/deny field, a webhook target, or a proxy destination taken as a plain host rather than parsed out of a URL.

Proof of concept

npm i ip-address@10.2.1, then:

js
const { Address4, Address6 } = require('ip-address');

// true => 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.

Blast Radius

ecosystem impact
† from your stack dependencies † transitive graph · vuln.today resolves 4-path depth
  • 1 npm packages depend on ip-address (1 direct, 0 indirect)

Ecosystem-wide dependent count for version 10.1.1.

Threat Intelligence Overview

EPSS Score
0.3%
Top 80% exploitable
Prevalence
Medium
npm library used in Node.js network-boundary and SSRF-protection code
Threat Intel
1
1 source
Exploit
POC
Public exploit code exists
Social Media
1
Sightings
Data Quality
7 sources
Confidence: High
EUVD NVD CVE.org EPSS Vulnrichment GHSA Vendor CIRCL GitHub VulDB

How this decision was reached

The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.

SignalValue
Severity MEDIUM
CISA KEV No
Public POC Yes
EPSS 0.3%
Patch available Yes
Active threat No
Deciding rule
MEDIUM severity (CVSS 4.0-6.9)
What every action level means
Emergency Immediate action required. Criteria: CRITICAL + in CISA KEV (actively exploited) without patch, OR CRITICAL + EPSS > 30% without patch, OR CRITICAL + active threat signals without patch.
Act Now Prioritize within 24-48h. Criteria: in KEV with patch available, OR CRITICAL + public POC, OR HIGH + EPSS > 10%, OR CRITICAL + active threat, OR any CRITICAL severity.
This Week Schedule remediation this week. Criteria: HIGH severity (CVSS 7.0-8.9). Patch within normal change window.
This Month Plan within 30 days. Criteria: MEDIUM severity (CVSS 4.0-6.9), lower exploitation probability. Include in regular patch cycle.
Monitor Track and reassess. Criteria: LOW severity (CVSS 0.1-3.9), minimal exploitation risk. No immediate action needed.

SSVC AssessmentENISA

SSVC Decision· derived
Scheduled
Exploitation
Poc
System Exposure· derived
Open
Automatable
No
Human Impact· derived
Medium
Technical Impact
Partial

Priority Score

54
Low Medium High Critical
KEV: 0
EPSS: 0
CVSS: +34
PoC: +20
Weaponized: 0
Threat intel: 0
Gov advisory: 0

Attack Technique

Server-Side Request Forgery exploits applications that fetch remote resources based on user-supplied URLs.

CVE-2025-68613 HIGH POC
8.8 Dec 19

Remote code execution in n8n's workflow expression evaluation system allows an authenticated user with workflow creation

CVE-2024-41713 CRITICAL POC
9.1 Oct 21

A vulnerability in the NuPoint Unified Messaging (NPM) component of Mitel MiCollab through 9.8 SP1 FP2 (9.8.1.201) could

CVE-2024-55591 CRITICAL POC
9.8 Jan 14

FortiOS and FortiProxy contain an authentication bypass via the Node.js websocket module allowing unauthenticated remote

CVE-2023-44487 HIGH POC
7.5 Oct 10

Denial of service against HTTP/2 server implementations allows remote unauthenticated attackers to exhaust server resour

CVE-2014-7205 CRITICAL POC
10.0 Oct 08

Eval injection vulnerability in the internals.batch function in lib/batch.js in the bassmaster plugin before 1.5.2 for t

CVE-2025-59528 CRITICAL POC
10.0 Sep 22

Flowise version 3.0.5 contains a remote code execution vulnerability in the CustomMCP node. The mcpServerConfig paramete

CVE-2017-14849 HIGH POC
7.5 Sep 28

Node.js 8.5.0 before 8.6.0 allows remote attackers to access unintended files, because a change to ".." handling was inc

CVE-2017-5941 CRITICAL POC
9.8 Feb 09

An issue was discovered in the node-serialize package 0.0.4 for Node.js. Rated critical severity (CVSS 9.8), this vulner

CVE-2014-0224 HIGH POC
7.4 Jun 05

OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph

CVE-2014-3744 HIGH POC
7.5 Oct 23

Directory traversal vulnerability in the st module before 0.2.5 for Node.js allows remote attackers to read arbitrary fi

CVE-2014-9566 HIGH POC
7.5 Mar 10

Multiple SQL injection vulnerabilities in the Manage Accounts page in the AccountManagement.asmx service in the Solarwin

CVE-2013-4660 MEDIUM POC
6.8 Jun 28

The JS-YAML module before 2.0.5 for Node.js parses input without properly considering the unsafe !!js/function tag, whic

Vendor StatusVendor

SUSE

Severity: Moderate
Product Status
SUSE Linux Enterprise High Performance Computing 12 Not-Affected
SUSE Linux Enterprise High Performance Computing 15 SP7 Not-Affected
SUSE Linux Enterprise High Performance Computing 15 SP7 Not-Affected
SUSE Linux Enterprise Module for Web and Scripting 15 SP7 Not-Affected
SUSE Linux Enterprise Module for Web and Scripting 15 SP7 Not-Affected

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy