Update dependency ip-address to v10.3.1 [SECURITY] - #67
Closed
renovate[bot] wants to merge 2 commits into
Closed
Conversation
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
github-actions
Bot
force-pushed
the
main
branch
from
August 4, 2026 06:50
bb9aec1 to
a09cf14
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.0→10.3.1ip-address has XSS in Address6 HTML-emitting methods
CVE-2026-42338 / GHSA-v2v4-37r5-5v8g
More information
Details
Summary
Address6.group()andAddress6.link()do not HTML-escape attacker-controlled content before embedding it in the HTML strings they return, andAddressError.parseMessage(emitted by theAddress6constructor for invalid input) can contain unescaped attacker-controlled content in one branch. An application that (1) passes untrusted input toAddress6and (2) renders the output of these methods, or the thrown error'sparseMessage, as HTML (e.g. viainnerHTML) is vulnerable to cross-site scripting. A related issue inv6.helpers.spanAll()produced malformed markup but was not exploitable; it is hardened in the same release for consistency.Details
Four related issues were identified and fixed together:
Address6.group(): zone ID injection. TheAddress6constructor stores the raw input (including any IPv6 zone ID) inthis.addressbefore zone stripping.group()then passedthis.addresstohelpers.simpleGroup(), which wrapped each:-separated segment in a<span>element without HTML-escaping the content. A zone ID containing HTML markup was embedded verbatim.Address6.link({ prefix, className }): attribute-value injection.link()concatenated user-suppliedprefixandclassNameinto thehref="…"andclass="…"attributes without escaping. A caller passing untrusted content through these options could inject event handlers (e.g.onmouseover) and achieve XSS.Address6constructor: leading-zero IPv4 error path. The leading-zero branch inparse4in6()builtAddressError.parseMessageby concatenating the raw address throughString.replace(). Becauseparse4in6()runs before the bad-character check, any characters in the groups preceding the IPv4 suffix flowed into the error's HTML unescaped. Consumers who renderparseMessageas HTML (its documented purpose — it already contains<span class="parse-error">markup) could be XSS'd by a crafted input such as<img src=x onerror=alert(1)>:10.0.01.1.v6.helpers.spanAll(): attribute-value injection (defense in depth).spanAll()embedded each character of its input into aclass="digit value-${n} …"attribute without escaping. Becausesplit('')limitsnto a single character this was not exploitable in practice, but it produced malformed markup and is fixed for consistency.Affected Versions
All versions up to and including
10.1.0.Patched Version
10.1.1.Impact
Real-world exposure is believed to be extremely limited. Analysis of all 425 dependent npm packages as well as GitHub code search found zero consumers of
group(),link(), orspanAll(): these HTML-emitting surfaces appear to be unused across published npm packages and public repositories. Applications using only the address-parsing and comparison APIs (isValid,correctForm,isInSubnet,bigInt, etc.) are not affected.Consumers who do render the output of
group(),link(),spanAll(), orAddressError.parseMessageas HTML against untrusted input should upgrade.PoC
Workarounds
If users cannot upgrade immediately:
Address6constructor, orgroup(),link(), orspanAll(), nor theparseMessagefield of any thrownAddressError, as HTML; treat these values as text only, or run them through DOMPurify before inserting into the DOM (DOMPurify's default configuration preserves the library's intended<span>wrapping while stripping any injected event handlers), orAddress6.isValid()and reject anything that contains a zone identifier (a%character) or characters outside[0-9a-fA-F:/]before passing it to the constructor.Lack of separate CVEs
Given the evidence that these methods are not used, and given that they are all of the same construction, maintainers do not think it's relevant or useful to create a separate CVE for each library method.
Credit
ip-address thanks @scovetta for reporting this issue.
Severity
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:L/VI:L/VA:N/SC:N/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
v10.1.1Compare Source
Configuration
📅 Schedule: (UTC)
🚦 Automerge: Enabled.
♻ Rebasing: Whenever PR becomes conflicted, 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.