chore(deps): update overrides ip-address to v10.3.1 [security] - #62
Closed
renovate[bot] wants to merge 1 commit into
Closed
chore(deps): update overrides ip-address to v10.3.1 [security]#62renovate[bot] wants to merge 1 commit into
renovate[bot] wants to merge 1 commit into
Conversation
Deploying stackhacker-ui-web with
|
| Latest commit: |
eb970cb
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://abc97743.stackhacker-ui-web.pages.dev |
| Branch Preview URL: | https://renovate-npm-ip-address-vuln.stackhacker-ui-web.pages.dev |
renovate
Bot
force-pushed
the
renovate/npm-ip-address-vulnerability
branch
from
August 5, 2026 14:02
ec209a1 to
eb970cb
Compare
Contributor
Author
Renovate Ignore NotificationBecause you closed this PR without merging, Renovate will ignore this update ( If you accidentally closed this PR, or if you changed your mind: rename this PR to get a fresh replacement PR. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
10.1.1→10.3.1ip-address: misclassification of IPv4-mapped/NAT64 IPv6 addresses can bypass SSRF and trust-boundary checks
CVE-2026-54272 / GHSA-22jq-vg5j-6vgg
More information
Details
Summary
Address6's special-property checks misclassify IPv4-mapped (::ffff:0:0/96) and NAT64 well-known (64:ff9b::/96) IPv6 addresses. These checks classify an address by its IPv6 wrapper rather than by the IPv4 address it embeds, soisLoopback(),isLinkLocal(),isMulticast(), andisUnspecified()all returnfalsefor literals such as::ffff:127.0.0.1or::ffff:169.254.169.254that actually route to loopback, RFC 1918, or link-local (cloud-metadata) destinations.Address6also had noisPrivate()method, so a mapped RFC 1918 address could not be detected at all.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
Address6.getType()classifies an address by matching it against a table of known IPv6 special-use prefixes, returningGlobal unicastwhen nothing matches. That table had no entry for the IPv4-mapped range (::ffff:0:0/96), so every mapped address fell through toGlobal unicast; NAT64 addresses matched their ownNAT64 …labels. The boolean checksisLoopback,isUnspecified, andisMulticastcomparedgetType()against a fixed label and so returnedfalse, whileisLinkLocalandisULAchecked only the native IPv6 ranges.The library already exposed
isMapped4()andto4(), but did not apply them inside these checks, so a mapped or NAT64 address was never normalized to its embedded IPv4 address before classification. The underlying CIDR matching is correct; the defect is that the special-use table omitted the IPv4-mapped range and the checks performed no embedded-IPv4 normalization.Affected versions
>= 10.1.1, <= 10.2.0. Theis*classification API was introduced forAddress4in 10.1.1 and extended toAddress6in 10.2.0. Releases before 10.1.1 do not expose this API and are not affected through this vector.Impact
The misclassification covers the entire
::ffff:0:0/96range, in both dotted and hex notation and case-insensitively, plus the64:ff9b::/96NAT64 well-known prefix:::ffff:127.0.0.1/::ffff:7f00:1127.0.0.0/8)::ffff:10.0.0.110/8::ffff:172.16.5.5172.16/12::ffff:192.168.1.1192.168/16::ffff:169.254.169.254/::ffff:a9fe:a9fe::ffff:100.64.0.1100.64/10::ffff:0.0.0.0/::ffff:255.255.255.25564:ff9b::7f00:1/64:ff9b::a9fe:a9feFor IPv4-mapped addresses the host OS routes to the IPv4 stack, so the misclassification is reachable on any dual-stack host. For NAT64, the classification bypass is unconditional but end-to-end reachability additionally requires a NAT64/DNS64 gateway in the deployment network.
Proof of concept
A guard assembled from these checks lets internal hosts through:
On affected versions this prints (note that every
::ffff:…and64:ff9b::…internal target is allowed):The first three lines (native loopback, native IPv6 loopback, and a literal RFC 1918 address) are blocked as expected; the IPv4-mapped and NAT64 forms of the same internal destinations are allowed through.
Remediation
Upgrade to the patched release. In the fix,
Address6normalizes IPv4-mapped and NAT64 well-known addresses to their embedded IPv4 address before classifying, via a newembeddedIPv4()helper thatisLoopback,isLinkLocal,isMulticast, andisUnspecifiedconsult first.Address6also gainsisPrivate(),isCGNAT(), andisBroadcast()for parity withAddress4, andgetType()now labels the::ffff:0:0/96range asIPv4-mapped. After upgrading,new Address6('::ffff:127.0.0.1').isLoopback()returnstrueandnew Address6('::ffff:10.0.0.1').isPrivate()returnstrue.If you cannot upgrade immediately, normalize embedded IPv4 addresses yourself before classifying: call
to4()on any address whereisMapped4()(or membership in64:ff9b::/96) is true, and run your IPv4 checks against the result.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 @OV-0-VO.
Severity
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:H/SI:N/SA:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
ip-address: a CIDR suffix on the parsed address suppresses special-use classification and can bypass SSRF and trust-boundary checks
CVE-2026-69198 / GHSA-4xrf-jv44-h6hh
More information
Details
Summary
Every special-use classification method is built on
isInSubnet, which short-circuits tofalsewhenever 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/0suppresses classification entirely:isLoopback(),isPrivate(),isLinkLocal(),isCGNAT(),isMulticast(),isUnspecified(),isBroadcast(),isULA(), andgetType()all report an internal address as unremarkable, whilecorrectForm()andaddressstill 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
isInSubnetinsrc/common.tsopens with a guard that compares the two prefix lengths:That guard is correct for the question
isInSubnetis named for — whether one network is contained in another, where a/0network 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./0is 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 returnsfalse.The underlying bit comparison is correct, and
mask(n)already returns the firstnbits of the full parsed address independently ofsubnetMask— the defect is solely that the containment guard sits in the classification path. Host bits are retained through parsing, socorrectForm()still yields the real target and the address remains fully usable for connecting./0is 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/7defeatsisPrivate()for10.0.0.0/8.Affected versions
>= 10.1.1, <= 10.2.1. Theis*classification API was introduced forAddress4in 10.1.1 and extended toAddress6in 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, butisInSubnetalone 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/0reverts to being reported as non-internal.Impact
Every classifier is affected on both
Address4andAddress6. The sole exception isAddress6.isLinkLocal()for nativefe80::/10addresses, which compares raw bits directly; its IPv4-mapped path is still affected.127.0.0.1/0127.0.0.0/8)10.0.0.1/0,10.0.0.5/710/8172.16.5.5/0172.16/12192.168.1.1/0192.168/16169.254.169.254/0100.64.0.1/0100.64/100.0.0.0/0,255.255.255.255/0::1/0fc00::1/0fc00::/7ff02::1/0::ffff:127.0.0.1/0::ffff:169.254.169.254/064:ff9b::7f00:1/0getType()returnsGlobal unicastfor all of the IPv6 cases above, andgetScope()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')parseshostnameas127.0.0.1andpathnameas/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:On affected versions every suffixed internal target is allowed, and
correctForm()shows the request would reach the real internal address: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 behindembeddedIPv4) uses it.isInSubnetkeeps 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()returnstrue.If you cannot upgrade immediately, strip the suffix before classifying by re-parsing
addressMinusSuffix: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.
Severity
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:H/SI:N/SA:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
ip-address: Address4 decodes leading-zero octets as decimal while resolvers decode them as octal, allowing SSRF and trust-boundary bypass
CVE-2026-69192 / GHSA-mwp4-54f8-5fhr
More information
Details
Summary
Address4accepts an octet written with a leading zero and decodes it as decimal, while the WHATWG URL host parser,inet_aton, andgetaddrinfoall decode a leading zero as octal. The library and the network stack therefore disagree about which host a string names.new Address4('012.0.0.1')reportscorrectForm()of12.0.0.1andisPrivate()offalse, butfetch('http://012.0.0.1/')connects to10.0.0.1.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) will classify 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
Address4.parsegates untrusted input onRE_ADDRESS(src/v4/constants.ts:5), whose per-octet alternative is:The
[01]?[0-9][0-9]?branch matches a leading zero, so012passes validation. Every downstream decode then reads the octet withparseInt(part, 10)(src/common.ts:87), yielding 12. A resolver reading the same string treats the leading0as base 8 and yields 10.The defect is in the parse gate rather than in any one classifier, so every consumer of
Address4inherits it:isPrivate(),isLoopback(),isLinkLocal(),isCGNAT(),isInSubnet(),isHostInSubnet(), andcorrectForm()are all computed from the mis-decoded octets.Address6already rejects this notation on its IPv4-in-IPv6 path, throwing "IPv4 addresses can't have leading zeroes." (src/ipv6.ts:751-762), soAddress4is the outlier within the library.Affected versions
<= 10.3.0. Unlike GHSA-22jq-vg5j-6vgg and GHSA-4xrf-jv44-h6hh, which were bounded below by theis*classification API introduced in 10.1.1, this defect is inparseand reaches every release: a guard built onisInSubnet()against the RFC 1918 ranges is affected in versions predating that API.Impact
The disagreement runs in both directions. Under-blocking is the security-relevant case; over-blocking is a correctness and availability problem.
correctForm()012.0.0.112.0.0.110.0.0.1012.012.012.01212.12.12.1210.10.10.10010.0.0.110.0.0.18.0.0.1Reachable targets are those whose leading octet is expressible as a three-character octal literal, which covers the whole of
10.0.0.0/8and0.0.0.0/8. A four-character octet such as0177for 127 is rejected by the regex, so loopback is not reachable through this path; see the note on rejection below for why rejection is not the same as safety.Reachability
A leading-zero address is a legal URL host, so this is reachable through the ordinary URL path with no unusual application shape required:
This distinguishes it from GHSA-4xrf-jv44-h6hh, where the
/0CIDR suffix could not survive URL parsing and exploitation therefore required an application that accepted a bare suffix-bearing string. Here the attack rides the same code path a normal user-supplied URL takes.Proof of concept
npm i ip-address@10.3.0, then:On affected versions:
The literal RFC 1918 address is blocked as expected; the octal-ambiguous spellings of the same destinations are allowed through.
Remediation
Upgrade to the patched release. In the fix,
Address4.parserejects any octet with a leading zero followed by further digits, mirroring the checkAddress6already applies atsrc/ipv6.ts:751, andRE_ADDRESSis tightened so those forms no longer appear in the valid corpus. After upgrading,Address4.isValid('012.0.0.1')returnsfalseand the constructor throwsAddressError.This rejects input that previous releases accepted. An application that deliberately feeds zero-padded addresses such as
010.010.010.010from a legacy system must strip the padding before parsing.If you cannot upgrade immediately, reject any host whose octets carry a leading zero before you parse it:
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.
One specific pitfall is worth naming, because the fix above does not remove it.
Address4.isValid()returningfalsemeans "this is not a dotted-quad IPv4 literal"; it does not mean "this is not an address that will reach an internal host". Every one of the following is rejected byisValid()and still resolves to loopback:A guard shaped
if (Address4.isValid(h)) { check() } else { treatAsHostname() }therefore routes all of them past the IP check. Rejecting these is correct behavior for an IPv4 parser and is not changed by this advisory, but a guard must treat "not a valid literal" as a case to resolve and re-check, never as a case to allow.Severity
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:H/SI:N/SA:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Release Notes
beaugunderson/ip-address (ip-address)
v10.3.1Compare Source
Full Changelog: beaugunderson/ip-address@v10.3.0...v10.3.1
v10.3.0Compare Source
Full Changelog: beaugunderson/ip-address@v10.2.2...v10.3.0
v10.2.2Compare Source
Full Changelog: beaugunderson/ip-address@v10.2.1...v10.2.2
v10.2.1Compare Source
Full Changelog: beaugunderson/ip-address@v10.2.0...v10.2.1
v10.2.0Compare Source
Configuration
📅 Schedule: (UTC)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.