fix(no_proxy): canonicalise IPv4 shorthand/octal/hex in shouldBypassProxy#11029
Merged
jasonsaayman merged 6 commits intoJun 29, 2026
Merged
Conversation
…roxy Node's URL parser accepts IPv4 in shorthand (127.1), octal (0177.0.0.1), and hex (0x7f.0.0.1) form and canonicalises it to dotted-decimal before the hostname reaches `shouldBypassProxy`. NO_PROXY entries, by contrast, were compared as raw strings, so an entry like `NO_PROXY=127.1` failed to match a request to `http://127.0.0.1/` — and symmetrically, an entry written in canonical form failed to match a request URL written in shorthand/octal/hex. This change adds a `normalizeIPAddress` helper that mirrors Node's per-part parsing (hex prefix → base 16, 0-prefixed multi-digit → base 8, otherwise base 10) and routes the result through the existing `normalizeNoProxyHost` so both sides of the comparison see the same canonical dotted-decimal form. The helper is fail-safe: out-of-range octets, invalid hex digits, 1-part inputs (which Node treats as a 32-bit integer), and 5+ parts return the input unchanged so the policy falls through to non-bypass. Adds 12 unit tests covering each shorthand/octal/hex form on both sides of the comparison, plus fail-safe cases (out-of-range, invalid hex digit, 1-part input).
…ntry Backfill the PR number that was a placeholder at commit time.
Contributor
There was a problem hiding this comment.
1 issue found and verified against the latest diff
Confidence score: 2/5
lib/helpers/shouldBypassProxy.jsnormalizes 2/3-part IPv4 hosts differently than Node’s WHATWG URL parser, soNO_PROXYmatching can diverge for multi-byte integer tails or hex/octal forms; merging as-is risks incorrect proxy bypass behavior for affected host inputs — align normalization with WHATWG parsing and add targeted tests for those address variants before merging.
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Cubic-bot P1 review on PR axios#11029 found that the shorthand-tail parser in `normalizeIPAddress` handled only single-digit decimal padding, while Node's URL parser parses the tail as a full IPv4 number (hex/octal/ decimal) and packs it low-byte-right into the remaining octets. Concrete cases that Node canonicalises but the previous implementation rejected: 127.65535 -> 127.0.255.255, 127.0x00ff -> 127.0.0.255, 127.0177 -> 127.0.0.127, 127.0.65535 -> 127.0.255.255, 0.0.0xff -> 0.0.0.255. Replace the decimal-only pad-and-split with the cubic-suggested implementation: parse the tail via the existing `parseIPv4Octet` helper (which already supports hex/octal/decimal per part), cap at `maxTail = (1 << (8 * tailSlots)) - 1`, and pack into the remaining octets from the right via `tailOctets[i] = v & 0xff; v >>= 8`. Out-of-range tails and non-numeric tails (which `parseIPv4Octet` returns `null` for) are returned unchanged so the policy falls through to non-bypass, preserving the fail-safe posture. The 1-part rejection (Node's 32-bit-integer semantics) is preserved deliberately: `NO_PROXY=0x7f` does not match `http://127.0.0.127/`, and a new test locks that asymmetry in. Adds 9 unit tests: 5 for the new shorthand-tail cases on both sides of the comparison, 1 for the 1-part hex lock-in, and 2 out-of-range fail-safe cases. All 12 prior shorthand/octal/hex tests and all 40 pre-existing tests in the file continue to pass.
Contributor
There was a problem hiding this comment.
1 issue found across 3 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
AnandSundar
added a commit
to AnandSundar/axios
that referenced
this pull request
Jun 22, 2026
…parse Cubic-bot P3 review on commit ed73218 (PR axios#11029) flagged that the test comment at tests/unit/helpers/shouldBypassProxy.test.js:471 incorrectly claimed the URL http://127.0.0.0:7777/ fails to parse. Node parses it cleanly (127.0.0.0:7777 is canonical IPv4 with port); the test passed for the right reason -- the entry NO_PROXY=127.16777216 is what gets returned unchanged because tail 16777216 (= 2^24) exceeds the 3-octet tail capacity 2^24 - 1, so the comparison falls through. Rewrite the comment to describe the entry-side mechanism accurately, and add an inline expect(new URL(...)).hostname === '127.0.0.0' assertion inside the same it() block so the URL-side parse is locked in. The misleading-comment class is now observable: any future change that breaks URL parsing of canonical IPv4 will fail this test loudly, not silently. The 3-part counterpart test (lines 478-484) already had a correct fail-safe comment and is untouched. PRE_RELEASE_CHANGELOG.md gets a one-sentence append inside the existing **NO_PROXY IPv4 normalization:** entry referencing the cubic review. All 61 tests in the file pass (60 prior + the rewritten it() block with its new inline assertion).
Contributor
There was a problem hiding this comment.
1 issue found across 2 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
…parse Cubic-bot P3 review on commit ed73218 (PR axios#11029) flagged that the test comment at tests/unit/helpers/shouldBypassProxy.test.js:471 incorrectly claimed the URL http://127.0.0.0:7777/ fails to parse. Node parses it cleanly (127.0.0.0:7777 is canonical IPv4 with port); the test passed for the right reason -- the entry NO_PROXY=127.16777216 is what gets returned unchanged because tail 16777216 (= 2^24) exceeds the 3-octet tail capacity 2^24 - 1, so the comparison falls through. Rewrite the comment to describe the entry-side mechanism accurately, and add an inline expect(new URL(...)).hostname === '127.0.0.0' assertion inside the same it() block so the URL-side parse is locked in. The misleading-comment class is now observable: any future change that breaks URL parsing of canonical IPv4 will fail this test loudly, not silently. The 3-part counterpart test (lines 478-484) already had a correct fail-safe comment and is untouched. All 61 tests in the file pass (60 prior + the rewritten it() block with its new inline assertion).
c586827 to
0e86fa0
Compare
jasonsaayman
approved these changes
Jun 29, 2026
Contributor
Author
|
@jasonsaayman Thank you for reviewing my PR and merging with master. I appreciate it. |
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.
fix(no_proxy): canonicalise IPv4 shorthand/octal/hex in shouldBypassProxy
🏄
Summary
shouldBypassProxycompared NO_PROXY entries against the request hostnameas raw strings. Node's URL parser, however, accepts IPv4 in shorthand
(
127.1), octal (0177.0.0.1), and hex (0x7f.0.0.1) form and silentlycanonicalises it to dotted-decimal before the hostname reaches the helper.
That asymmetry let a NO_PROXY entry like
127.1fail to match a request tohttp://127.0.0.1/, and — more importantly — let an entry written incanonical form silently fail to match a request URL whose host was written
in shorthand/octal/hex. The latter is a parser-differential bypass:
NO_PROXY=127.0.0.1is supposed to keep loopback traffic off the proxy,but a request to
http://0177.0.0.1/(Node-canonicalised to127.0.0.1)did not match the canonical entry and so went through the proxy.
This change adds a
normalizeIPAddresshelper that mirrors Node's per-partparsing (hex prefix → base 16,
0-prefixed multi-digit → base 8, otherwisebase 10) and routes the result through the existing
normalizeNoProxyHostso both sides of the comparison see the same canonical dotted-decimal form.
The helper is fail-safe: out-of-range octets, invalid hex digits, 1-part
inputs (which Node treats as a 32-bit integer, e.g.
127→0.0.0.127),and 5+ parts return the input unchanged so the policy falls through to
non-bypass.
Closes the NO_PROXY parser-differential gap that v1.18.0's URL-and-request
hardening pass (#11000) did not cover.
Changes
lib/helpers/shouldBypassProxy.js: addparseIPv4OctetandnormalizeIPAddress; routenormalizeNoProxyHostthrough the helperbefore falling back to the existing IPv4-mapped IPv6 unmap.
tests/unit/helpers/shouldBypassProxy.test.js: 12 new cases in a newdescribe('IPv4 shorthand / octal / hex normalization', …)block,covering each shorthand/octal/hex form on both sides of the comparison
and three fail-safe cases (out-of-range, invalid hex digit, 1-part).
PRE_RELEASE_CHANGELOG.md: one-line entry under Bug Fixes per therepo's contributor guide (which prefers the pre-release changelog over
CHANGELOG.mdfor unreleased changes).Test plan
npx vitest run tests/unit/helpers/shouldBypassProxy.test.js—52/52 pass (40 pre-existing + 12 new).
npm run test:vitest— full suite green.Checklist
index.d.ts/index.d.ctschange needed.package-lock.json(the existing lockfile isconsistent with the existing
package.jsonafter a cleannpm ci).Summary by cubic
Fixes NO_PROXY mismatches by normalizing IPv4 shorthand, octal, and hex hostnames in
shouldBypassProxyto dotted-decimal to match Node’s URL parser. Also adds safe tail expansion for shorthand forms and rejects invalid zero-prefixed decimals and out-of-range tails.Description
normalizeIPAddressandparseIPv4Octetto canonicalize IPv4 shorthand, octal (0177.0.0.1), and hex (0x7f.0.0.1) to dotted-decimal.127.65535→127.0.255.255.08), out-of-range octets/tails, and 1-part or 5+ parts.normalizeNoProxyHostthrough the new helper before IPv4-mapped-IPv6 unmapping.URLparse assertion.Docs
Add a note in
/docs/thatNO_PROXYIPv4 entries are normalized to dotted-decimal and match shorthand, octal, and hex forms accepted by Node’s parser. Include brief examples for multi-byte tail expansion and list fail-safes (invalid digits, out-of-range tails, single-part inputs).Testing
tests/unit/helpers/shouldBypassProxy.test.jscovering:URLhostname assertion.Semantic version impact
Patch: bug fix with no API changes.
Written for commit 00ab59b. Summary will update on new commits.