Aug 4, 2026·6 min read·1 visit
A design flaw in the `ip-address` library's classification logic allows attackers to bypass SSRF filters. Adding a `/0` suffix short-circuits internal checks, making local/private IPs look public.
An input validation vulnerability in the npm package `ip-address` allows unauthenticated remote attackers to bypass Server-Side Request Forgery (SSRF) protections by appending a `/0` CIDR suffix to IP address strings. This causes the library's classification helper functions to incorrectly identify internal addresses as public, external addresses, while normalization helpers resolve the address back to its internal form during network connection establishment.
The npm library ip-address is a widely utilized package for parsing, validating, and manipulating IPv4 and IPv6 addresses within Node.js applications. A critical utility of such a library is providing trust-boundary checks, enabling developers to classify IP addresses into categories such as private, loopback, or link-local. These classifications are frequently used to enforce Server-Side Request Forgery (SSRF) defenses, blocking connections to internal networks.
The vulnerability designated as CVE-2026-69198 (GHSA-4xrf-jv44-h6hh) arises from a fundamental confusion between network containment semantics and host address classification. When parsing user-supplied IP addresses containing trailing CIDR suffixes, the library evaluates these addresses against reference internal ranges. Because of an incorrect short-circuit guard in the comparison logic, appending a /0 suffix causes the library to treat local and private addresses as external, while other methods still return the normalized, unmasked local address.
This flaw results in a complete bypass of security boundaries in applications that rely on isPrivate(), isLoopback(), or similar classification functions to restrict outgoing connections. Because the connection logic subsequently normalizes the address back to the actual local target, the application executes requests to internal hosts under the assumption that they are safe external targets.
The underlying flaw is located in the isInSubnet method, defined within the common codebase (src/common.ts). This method was designed to serve two distinct functions: validating whether a network range is fully enclosed by another subnet, and checking if an individual IP address matches a predefined classification range (such as RFC 1918 or Loopback blocks).
To determine containment, the library evaluates if the subnet mask of the current parsed IP is narrower than the reference range mask. It does so using the guard clause if (this.subnetMask < address.subnetMask) { return false; }. If an attacker inputs an IP address with a /0 prefix, such as 127.0.0.1/0, the parsed object is instantiated with a subnetMask property of 0.
When the application invokes a helper classifier like isLoopback(), the library compares the input instance to the static loopback subnet (e.g., 127.0.0.0/8 for IPv4). Inside isInSubnet, the evaluation is mapped as this.subnetMask < address.subnetMask, which evaluates to 0 < 8. Because this comparison is true, the method immediately returns false. This short-circuit bypasses the actual bitwise comparison of the IP address, leading the library to report that 127.0.0.1/0 is not a loopback address.
A side-by-side analysis of the vulnerable and patched code reveals how the boundary checks were separated. In the vulnerable version of src/common.ts, the implementation of isInSubnet conflated host classification and network containment.
// Vulnerable Implementation in src/common.ts
export function isInSubnet(this: Address4 | Address6, address: Address4 | Address6) {
// If the input address has a smaller mask (wider subnet) than the reference range,
// it immediately returns false. This is incorrect for host classification.
if (this.subnetMask < address.subnetMask) {
return false;
}
if (this.mask(address.subnetMask) === address.mask()) {
return true;
}
return false;
}The patch merged in version 10.2.2 resolves this issue by introducing isHostInSubnet. This function evaluates only the host bits against the reference mask, intentionally ignoring the parsed address's own subnet mask property.
// Patched Implementation in src/common.ts
export function isInSubnet(this: Address4 | Address6, address: Address4 | Address6) {
if (this.subnetMask < address.subnetMask) {
return false;
}
return isHostInSubnet.call(this, address);
}
export function isHostInSubnet(this: Address4 | Address6, address: Address4 | Address6) {
// Directly performs the mask comparison without evaluating the input's subnet mask
return this.mask(address.subnetMask) === address.mask();
}Additionally, the library's classifiers in src/ipv4.ts and src/ipv6.ts were refactored to consume isHostInSubnet instead of isInSubnet. This ensures that classification results remain consistent and are not influenced by the user-defined CIDR suffix.
An attacker targeting an SSRF protection filter can exploit this vulnerability by submitting a crafted IP string with a /0 suffix. The typical attack flow starts with the target application accepting user-supplied network input to perform an outbound request, validating the destination IP using the library's built-in checks prior to execution.
const { Address4 } = require('ip-address');
const axios = require('axios');
// Vulnerable application handler
async function fetchExternalResource(userInput) {
const parsed = new Address4(userInput);
// The filter attempts to block internal loopback/private destinations
if (parsed.isPrivate() || parsed.isLoopback()) {
throw new Error("Forbidden address");
}
// Normalization ignores the CIDR block, resolving the string to '127.0.0.1'
const safeUrl = `http://${parsed.correctForm()}/endpoint`;
return await axios.get(safeUrl);
}If the attacker inputs 127.0.0.1/0, the security checks return false, allowing the execution to proceed. When the HTTP client establishes the connection, it connects directly to 127.0.0.1. The application makes the connection internally, bypassing the SSRF defense entirely.
The impact of CVE-2026-69198 is severe for applications that rely on the library to maintain trust boundaries. By bypassing the private and loopback filters, an unauthenticated attacker can force the backend application server to interact with arbitrary internal network services.
This enables attackers to access restricted internal endpoints, cloud metadata services (e.g., AWS IMDSv1/v2 at 169.254.169.254), internal databases, and administration consoles. In microservice architectures, this bypass allows complete lateral movement, potentially leading to unauthorized data exposure, configuration modification, or remote code execution via vulnerable internal APIs.
While the CVSS base score is 6.9, the impact on subsequent systems is high (SC:H). This indicates that although the host library itself does not suffer direct data modification or service interruption, the backend infrastructure exposed by the SSRF bypass faces severe confidentiality threats.
The primary remediation path is upgrading the ip-address dependency to version 10.2.2 or later. This version correctly implements host classification and prevents CIDR suffixes from affecting loopback or private range checks.
For legacy deployments where immediate package upgrades are not feasible, developers must implement strict input sanitization. All user-supplied IP strings should be stripped of CIDR suffixes prior to parsing. This can be achieved using a regular expression to validate the absence of the / character, or by manually truncating the string at the first occurrence of the forward slash.
// Temporary Workaround: Strip CIDR suffix before parsing
function sanitizeIpInput(input) {
const parts = input.split('/');
return parts[0]; // Retains only the host portion
}Additionally, security teams should audit internal codebases for direct calls to isInSubnet. If custom code calls isInSubnet directly to validate host containment against a private range, it must be migrated to isHostInSubnet to prevent similar bypass techniques.
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| Product | Affected Versions | Fixed Version |
|---|---|---|
ip-address beaugunderson | >= 10.1.1, < 10.2.2 | 10.2.2 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-20, CWE-918 |
| Attack Vector | Network (AV:N) |
| CVSS Score | 6.9 (Medium) |
| Exploit Status | Proof of Concept available |
| KEV Status | Not Listed |
| Impact | Server-Side Request Forgery Bypass |
The product receives input that is intended to be parsed or validated but lacks correct, comprehensive, or isolated validation checks, leading to a bypass of security controls.
A trust-boundary bypass and Server-Side Request Forgery (SSRF) vulnerability exists in the ip-address library versions 10.1.1 through 10.2.0 due to structural input misclassification. The library fails to resolve and normalize transition IP notations, such as IPv4-mapped IPv6 (::ffff:0:0/96) and NAT64 (64:ff9b::/96) addresses, to their embedded IPv4 representations prior to evaluation. Consequently, standard security validation checks (e.g., isLoopback, isLinkLocal, isULA) return false for these addresses. This allows remote attackers to bypass application-level IP address filters, gaining unauthorized access to internal resources, cloud metadata interfaces, and local services on dual-stack hosts or environments utilizing NAT64 gateways.
A critical authentication bypass vulnerability (CVE-2026-18574) in Check Point Security Management and Multi-Domain Security Management (MDS) Servers allows unauthenticated remote attackers to execute arbitrary system commands with administrative privileges. The flaw stems from an alternate path authentication bypass (CWE-288) in the management interface daemons.
An argument injection vulnerability in GitPython allows remote or local attackers to execute arbitrary file reads or arbitrary file overwrites via unsafe command option forwarding. This occurs because the wrapper methods `IndexFile.checkout()` and `TagReference.create()` fail to validate parameters before passing them to system-level git invocations.
An argument injection vulnerability in GitPython allows remote or local attackers with control over repository archive configuration options to retrieve arbitrary local files via native git archive commands. During clone operations, a sibling missing validation vulnerability in the clone option engine allows attackers to perform Server-Side Request Forgery via the git clone bundle-uri mechanism.
GitPython prior to version 3.1.56 is vulnerable to argument injection in the Commit.count method. An attacker who controls keyword arguments passed to this method can inject arbitrary Git options, such as --output, leading to arbitrary file truncation on the host filesystem.
A critical SQL injection vulnerability was discovered in Sequelize when configured to use the Oracle database dialect. Due to a flawed optimization design in the SQL escaping subsystem (src/sql-string.js), strings that begin with native Oracle date functions bypass standard escaping. This allows unauthenticated remote attackers to execute arbitrary SQL commands on the target database.