Repository navigation
Fix the undici proxy bypass and align clients, types, and CI - #80
Draft
proxymeshai wants to merge 1 commit into
Draft
proxymeshai wants to merge 1 commit into
proxymeshai wants to merge 1 commit into
Conversation
HTTPS requests passed an open tunnel socket as undici connect.socket, which the default connector replaces with a direct dial, leaking the client IP. Use a custom connector on ProxyHeadersAgent and fail tests unless the mock proxy sees CONNECT and tunneled bytes. Also accept ky 2.2 Responses, widen peer ranges through the versions we test, require Node >= 22.19, and add unit, type, and latest-client workflows. Co-authored-by: ProxyMesh AI <proxymeshai@users.noreply.github.com>
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 is a security fix and warrants a patch release. This PR does not bump the version, tag, or open a
release/*branch. Auto-merge is off.Verified 2026-10-22 against a local mock CONNECT proxy. The undici adapter was handing undici an already-open tunnel socket (
connect: { socket }). Undici's default connector only usessocketas the HTTP socket for a TLS upgrade and otherwise dials the origin itself (undicilib/core/connect.js). On undici 7.30.1 and 8.12.2, zero bytes went through the proxy, so the caller's real IP leaked.What changed
Undici no longer bypasses the proxy. HTTPS now uses a custom
undici.Clientconnector that callsProxyHeadersAgent.createConnection(CONNECT, then TLS on that socket) and reads CONNECT response headers withgetProxyHeadersFromSocket. Plain HTTP usesundici.ProxyAgentand its native CONNECTheadersoption (undici PR #1877), with a fallback for olderProxyAgentconstructors.requestTls/tlsOptionsare applied.test/test_proxy_traversal.jsfails unless the mock proxy saw the CONNECT and tunneled bytes in both directions (a direct origin dial would still return 200 and fail this assertion).ky 2.2.0. ky 2.2 requires
fetchto resolve to a realResponse(instanceof globalThis.Responseor[object Response]). The adapter now converts the node-fetch body to a nativeResponseon ky 2 and keeps the previousProxyResponsepath on ky 1.proxyHeadersis an own property of thatResponse(clone()does not copy it).TypeScript 7. Removed
baseUrl(andignoreDeprecations) fromtsconfig.json.pathsstay relative to the tsconfig file.npm run test:typespasses on the repo's TypeScript 7.Peer ranges and engines. Widened to the majors exercised here, and left every peer optional in
peerDependenciesMeta(already optional):^12 || ^13 || ^14 || ^15 || ^16^5 || ^6 || ^7 || ^8^14 || ^15 || ^16^2 || ^3^1 || ^2(unchanged range; ky 2 is now actually supported)engines.nodeis>=22.19.0, matching undici 8.npm i javascript-proxy-headers got@16no longer ERESOLVEs for got 16, undici 8, make-fetch-happen 16, or typed-rest-client 3. make-fetch-happen 16's own engines are stricter (^22.22.2 || ^24.15.0 || >=26); current Node 22 and 24 releases satisfy that. Node 25 and 26 are not in the CI matrix.typed-rest-client v3. The adapter still subclasses
HttpClientand overrides_getAgent(TypeScriptprivatecompiles to a normal prototype method; v3.1.2 still callsthis._getAgentfrom_prepareRequest). A traversal test asserts the override returnsproxyAgentand that CONNECT plus tunneled bytes hit the mock proxy. Checked on 2.3.1 and 3.1.2.awaiton async factories. README, JSDoc, and examples forcreateProxyAxios,createProxyGot, andcreateProxySuperagentnowawaitthe factory (ky and wretch examples already did). Copying the old README threwclient.get is not a function. The.d.tsfactories already returnedPromise<...>;createProxyMakeFetchHappenandcreateProxyRestClientstay synchronous.types/undici.d.tsandtypes/ky.d.tsdocumenttlsOptions/requestTls.Package metadata (code only). npm
descriptionand keywords now includeproxy-headers,https-proxy,https-proxy-agent,proxy-agent,rotating-proxy,node-fetch, andx-proxymesh-ip. Homepage was alreadyhttps://github.com/proxymesh/javascript-proxy-headers. README badge sits under the H1, relative notes/license links are absolute, and there are cross-links to python-proxy-headers, ruby-proxy-headers, and scrapy-proxy-headers.jsr.jsonhas no description field (JSR reads that from package settings).CI (
.github/workflows/ci.yml): on pull requests and pushes tomain, jobs for unit tests,npm run test:types, and the local mock-proxy suite, each on a Node 22 and 24 matrix.runs-on: ubuntu-24.04only..github/workflows/latest-clients.ymlruns on a weekly Monday cron andworkflow_dispatch:npm ci, thennpm install --no-save --no-package-lockof the latest axios, got, ky, make-fetch-happen, needle, node-fetch, superagent, typed-rest-client, undici, and wretch, then unit tests and the local mock-proxy run (including the proxy-traversal assertion). It does not run on pull requests. Existingproxy_integration_tests.yml(realPROXY_URL) is unchanged.Dependabot
Dependabot auto-merge is unchanged.
.github/workflows/dependabot-auto-merge.ymlstill auto-approves and auto-merges every Dependabot version update, including major devDependency updates, once required checks pass.Owner settings (not changed here)
Please set these in the GitHub / JSR UI. This PR does not touch repo settings.
Send and read custom proxy headers on HTTPS CONNECT for axios, got, node-fetch, undici, ky and morehttps,connect,tunnel,proxymesh,http-client,typescriptjsr.json): set the same description (currently empty). Runtime compatibility: only Node is claimed. Do not mark Bun or Deno; this package usesnode:httpandnode:tlsand those runtimes were not tested.npx jsr publish,id-token: write) for the JSR provenance score point. Not done in this PR.Tests run locally (Node v22.23.4)
npm run test:unit: 20 tests passed (existing CONNECT security tests plus four traversal tests) on the lockfile and again after installing the latest supported clients.npm run test:types: passed on TypeScript 7.npm run test:local-proxy: 11/11 adapters, and the mock proxy recorded CONNECT plus tunneled bytes, on the lockfile and on latest clients (axios 1.20.0, got 16.1.0, ky 2.2.0, make-fetch-happen 16.0.1, needle 3.5.0, node-fetch 3.3.2, superagent 10.4.1, typed-rest-client 3.1.2, undici 8.12.3, wretch 3.0.9).ProxyResponse; ky 2.2.0 returns a nativeResponse.npm packstyle install of this tree plusgot@16,undici@8,make-fetch-happen@16, andtyped-rest-client@3did not ERESOLVE.Left out on purpose
DEP0123whenservernameis an IP address (ProxyHeadersAgentsetsservernameto the target host). Pre-existing; not changed.PROXY_URLsecret and is unchanged.workflow_dispatchonly, so it does not run on this pull request.