Sep 29, 2026·6 min read·27 visits
The `ip-address` library fails to identify the NAT64 local-use range 64:ff9b:1::/48 as private, enabling unauthenticated attackers to bypass SSRF validation checks and access internal network environments.
A validation bypass vulnerability exists in the npm package `ip-address` from version 10.2.0 to 10.5.1. The library's `Address6.isPrivate()` classifier fails to recognize the NAT64 local-use prefix range 64:ff9b:1::/48 as a restricted, private subnet. In networks implementing NAT64 routing configurations, an attacker can exploit this flaw to execute Server-Side Request Forgery (SSRF) and bypass local trust-boundary validations.
The ip-address library is an open-source JavaScript utility used to parse, validate, and manipulate IPv4 and IPv6 addresses. Applications frequently employ this library in network validation layers, specifically to distinguish between public and private/internal IP addresses before executing outbound network calls. This verification mechanism helps defend against Server-Side Request Forgery (SSRF) vulnerabilities.
From version 10.2.0 up to (but not including) 10.5.1, the library contains a classification flaw where the Address6.isPrivate() classifier fails to recognize the NAT64 local-use prefix range 64:ff9b:1::/48. Because this block is treated as globally routable public space rather than private or restricted space, the classification method returns false when querying addresses within this range.
This behavior creates a trust-boundary bypass. If an application uses the library to sanitize destination hosts on a network that implements local-use NAT64 routing, an attacker can input crafted IPv6 addresses to interact with internal services. The resulting bypass can expose sensitive internal endpoints to unauthenticated remote access.
The root cause of this vulnerability lies in the structural difference between standard NAT64 Well-Known Prefixes (WKP) and operator-selected NAT64 local-use prefixes. RFC 6052 defines the Well-Known Prefix as 64:ff9b::/96, where the embedded IPv4 address resides statically in the last 32 bits of the IPv6 address. The ip-address library parses these addresses by extracting the trailing 32 bits into an IPv4 object and delegating validation to that object.
In contrast, RFC 8215 defines the local-use prefix range 64:ff9b:1::/48 for stateful NAT64 translation. In this range, network operators can allocate prefixes of varying lengths, such as /48, /56, /64, or /96, as outlined in RFC 6052. Because the prefix length is variable, the library cannot assume a fixed 32-bit offset to locate and decode the embedded IPv4 address.
Prior to version 10.5.1, the isPrivate() method in src/ipv6.ts attempted to resolve an embedded IPv4 address via embeddedIPv4(). When parsing an address from the 64:ff9b:1::/48 range, this helper returned null due to the lack of a standardized offset. Since the library did not explicitly check for the 64:ff9b:1::/48 prefix, it bypassed the private address validation and defaulted to classifying the address as a public, globally unique unicast address.
A detailed review of the codebase reveals that the vulnerability is situated within the isPrivate() function in the Address6 class. In vulnerable versions, the function first checks for an embedded IPv4 address. If no embedded address is found, the logic falls back to checking whether the address is a Unique Local Address (ULA) via the isULA() helper method.
Below is the vulnerable implementation from src/ipv6.ts:
// VULNERABLE LOGIC in src/ipv6.ts
isPrivate(): boolean {
const embedded = this.embeddedIPv4();
if (embedded) {
return embedded.isPrivate();
}
return this.isULA();
}The patch introduced in commit ab3dc88bcf5374344168a2ba075ca7ac4ff257f8 mitigates this flaw. The fix defines a constant representing the NAT64 local-use subnet block and updates isPrivate() to explicitly evaluate whether the parsed address resides within that range.
Below is the patched logic with the added subnet check:
// PATCHED LOGIC in src/ipv6.ts
const NAT64_LOCAL_USE_SUBNET = new Address6('64:ff9b:1::/48');
// ...
isPrivate(): boolean {
const embedded = this.embeddedIPv4();
if (embedded) {
return embedded.isPrivate();
}
// Explicitly check for the RFC 8215 NAT64 local-use subnet range
return this.isULA() || this.isHostInSubnet(NAT64_LOCAL_USE_SUBNET);
}This modification ensures that any address belonging to the 64:ff9b:1::/48 subnet is classified as private, regardless of whether a specific embedded IPv4 address can be successfully extracted. This approach represents a complete fix for the reported variant because it treats the entire reserved subnet as private at the boundary level.
Exploitation of this vulnerability requires specific network environmental factors. The target application must deploy the vulnerable ip-address library within its validation tier and run within an internal network utilizing a stateful NAT64 translation gateway configured with the RFC 8215 prefix. Additionally, the application must accept user-defined hosts and resolve them to initiate outbound HTTP requests.
An attacker can trigger Server-Side Request Forgery (SSRF) by supplying a URL containing a crafted IPv6 address that maps to an internal IPv4 resource. For example, to target the AWS Instance Metadata Service (IMDSv1) at 169.254.169.254 (represented as a9fe:a9fe in hex), the attacker constructs an IPv6 address using the local-use prefix 64:ff9b:1::/48. Under a /48 prefix layout, the address resolves to 64:ff9b:1:a9fe:a9:fe00::.
Upon receiving this input, the application evaluates the IP with isPrivate(), which incorrectly returns false. The HTTP client then issues the connection. The outbound packet reaches the NAT64 gateway, which strips the local-use prefix, extracts the embedded IPv4 payload, and forwards the translated request to the targeted internal service, returning the response to the attacker.
The successful exploitation of this vulnerability leads to an internal trust-boundary bypass. This bypass enables Server-Side Request Forgery (SSRF) to occur, letting an unauthenticated remote attacker probe, access, or manipulate internal assets. These internal assets typically include loopback services, databases, metadata endpoints, and other microservices located behind the initial firewall.
The CVSS v4.0 base score is calculated at 6.9 (Medium) with the vector string 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. The score reflects low direct confidentiality impact on the host system, but high subsequent confidentiality impact on the target backend systems. The attack complexity is low, but it requires the target environment to be deployed on a network using NAT64 translation.
While there is no evidence of active exploitation in the wild or weaponized public exploits, the vulnerability remains a risk for containerized environments, Kubernetes clusters, and cloud environments that transition between IPv4 and IPv6 networks using local-use prefixes.
The primary remediation strategy is upgrading the ip-address library to version 10.5.1 or later, which incorporates the fix. The updated library correctly classifies the entire 64:ff9b:1::/48 range as private. This change resolves the trust-boundary bypass without requiring modifications to the application's verification logic.
If upgrading is not immediately possible, organizations can apply a manual workaround in their validation wrapper. Developers should manually check whether resolved IPv6 addresses reside within the 64:ff9b:1::/48 subnet using custom routing validation before issuing outbound network requests. This check must be performed prior to passing the address to the application client.
Additionally, defense-in-depth measures should be established at the network layer. Restrict the outbound capabilities of the application runtime environment by implementing network policies that block egress traffic to the NAT64 gateway from unauthorized containers. Implementing DNS rebinding protection and ensuring that HTTP clients pin connections to resolved socket IPs rather than re-resolving the hostnames are also recommended.
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 Beau Gunderson | >= 10.2.0, < 10.5.1 | 10.5.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-918: Server-Side Request Forgery (SSRF) |
| Attack Vector | Network (Unauthenticated) |
| CVSS v4.0 Score | 6.9 (Medium) |
| EPSS Score / Percentile | Not available / No active threat intel indicators |
| Exploit Status | poc |
| KEV Status | Not listed on CISA KEV |
The application takes a user-supplied URL or IP destination and executes a request without validating the resolved address appropriately, enabling internal resource probing.
CVE-2026-126081 is a mass-assignment vulnerability (CWE-915) in the Action Pack component of Ruby on Rails. Prior to versions 8.1.4.1 and 8.0.5.2, the ActionController::Parameters#each_key method was delegated directly to the internal ActiveSupport::HashWithIndifferentAccess instance holding raw request parameters. When invoked with a block, #each_key returned the underlying unpermitted hash rather than the ActionController::Parameters wrapper instance. Applications that pass the return value of #each_key directly into Active Model mass-assignment methods bypass Strong Parameters enforcement, allowing attackers to modify restricted model attributes.
A vulnerability classified under CWE-345 (Insufficient Verification of Data Authenticity) exists in the Active Storage component of Ruby on Rails prior to versions 8.1.4.1 and 8.0.5.2. When Google Cloud Storage (GCS) is configured as the storage backend with the cache_control option enabled, Active Storage switches from GCS V2 signing to V4 signing for direct upload URLs. Because the V4 signing implementation only binds the Cache-Control and Host headers, the Content-Type and Content-MD5 headers remain unsigned. An attacker can modify the Content-Type header during a direct upload request to store HTML or SVG files with active JavaScript on the GCS bucket origin, enabling Service Worker registration and interception of subsequent signed URL responses within the bucket path.
A Cross-Site Scripting (XSS) vulnerability exists in Ruby on Rails Action View prior to versions 8.0.5.2 and 8.1.4.1. When applications use the default HTML5 sanitizer (Rails::HTML5::Sanitizer) with Nokogiri versions prior to 1.19.5, angle brackets (< and >) inside HTML attribute values are serialized unescaped. Action View text helpers—specifically highlight and simple_format—perform string-based manipulations on the sanitized HTML rather than operating on the DOM tree. An unescaped '>' character or a double newline ('\n\n') inside an attribute value causes these helpers to misidentify tag or paragraph boundaries, breaking out of the attribute context and emitting inert attribute contents as live HTML elements in the final html_safe output.
CVE-2026-126070 is a Cross-Site Scripting (XSS) vulnerability in the Action View component of Ruby on Rails. Prior to versions 8.0.5.2 and 8.1.4.1, the strip_tags helper returned sanitized output marked as html_safe without encoding single or double quotation marks. When applications render the output of strip_tags inside quoted HTML attributes in ERB templates, attackers can break out of the attribute context and inject arbitrary HTML attributes or JavaScript event handlers.
CVE-2026-126078 is a Cross-Site Scripting (XSS) vulnerability classified under CWE-79 affecting the Action View component of Ruby on Rails in versions prior to 8.0.5.2 and 8.1.4.1. The vulnerability resides in the ActionView::Helpers::TextHelper#highlight method when invoked with a custom :highlighter template that places capture group placeholders inside HTML attribute values. Because matched substrings are substituted without HTML escaping after initial sanitization preserves literal quotation marks, an attacker controlling the input text or target search phrase can break out of the surrounding attribute delimiter and inject arbitrary HTML attributes or JavaScript event handlers.
An information exposure vulnerability in Ruby on Rails Action Pack allows sensitive session cookies to be attached to public, cacheable responses served by Active Storage proxy controllers. When cookie secret rotation or a hybrid cookie serializer migration is enabled, reading a legacy-format cookie triggers an automatic cookie rewrite that ignores the session-skipping directive. If an intermediate shared cache or CDN caches the resulting response along with its Set-Cookie header, subsequent users requesting the same URL receive the leaked session token.