Repository navigation
fix(ssrf): isolate pinned connections from pooled sockets; bump dependencies - #37
Conversation
Node's global http agent keeps sockets alive and pools them by host:port, ignoring the request's lookup. A pinned request could therefore reuse a socket another client in the process had connected to a different (internal) address, skipping the pin. The pinned transport now uses a one-off agent per request so every hop dials through the pinned lookup. Adds regression tests for DNS rebinding through safeFetch, fromURL and external $ref resolution (validation answers public, a connect-time lookup would answer loopback), and for the pooled-socket case. Documents the pinning guarantees in docs/ssrf-prevention.md.
…ire Node >= 22.19 json-schema-ref-parser 16 drops Node.js versions before 22.19.0 (Node 20 reached end-of-life in April 2026) and ships upstream reference-handling hardening. Raise engines.node to match and drop 20.x from the CI matrix. BREAKING CHANGE: Node.js >= 22.19.0 is now required.
…ode 26, @types/jest 30, zod 4.6 - @types/node 26 types Uint8Array views as Uint8Array<ArrayBufferLike>, which is not a BlobPart; copy multipart binary parts into a plain ArrayBuffer-backed view before wrapping them in a Blob. - Jest 30 renamed --testPathPattern to --testPathPatterns.
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Essentials Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (8)
Included review availability: This review used your included allowance. 1 included review remains after this review. Your included PR review attempts over the past 7 days set your current allowance at 2 reviews per hour. WalkthroughNode requests now use fresh sockets to preserve pinned-address behavior. The changes add DNS-rebinding and socket-pooling tests, update Node and test-tool versions, document SSRF safeguards, and copy multipart byte arrays before creating a Blob. ChangesPinned request transport
Test and parser toolchain
Multipart byte serialization
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~20 minutes Change: Bug fix Merge Risk: ⚪ Minimal · up to No merge-blocking issue is established; the change is ready for normal checks. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
A rabbit checks the pinned address with care. Comment |
Summary
SSRF hardening: pinned transport never reuses pooled sockets
Since 2.5.1,
safeFetchpins every Node connection to the addressassertUrlSafevalidated, through a customlookup. That closes the DNS-rebinding window between the check and the connect. There was one remaining gap: Node ≥ 19'shttp.globalAgentkeeps sockets alive and pools them byhost:port, ignoringlookup. A pinned request could reuse a keep-alive socket that another client in the process had already connected to a different (internal) address.nodePinnedTransportnow passesagent: false, so every request and every redirect hop opens a fresh socket through the pinned lookup.Regression tests
ssrf.spec.ts). First, warmhttp.globalAgentwith a socket to127.0.0.1. Then a request to the samehost:portpinned to a public address must not reach the loopback server. This test failed before the fix.ssrf.spec.ts,generator.spec.ts). Validation answers a public address and a connect-timedns.lookupwould answer loopback.safeFetch,fromURLand external$refresolution must never reach the loopback server, and must never call the connect-time lookup. I checked that all three fail when the pinnedlookupis removed.Docs
docs/ssrf-prevention.md"How It Works" now covers DNS validation, connection pinning, fresh sockets and per-hop redirect checks, plus the limits offetchImpland edge runtimes.Dependency updates (supersedes #34, #35, #36)
yaml2.9.0 → 2.9.1@apidevtools/json-schema-ref-parser15.5.1 → 16.0.3 (range^16.0.2)jest30,@swc/core1.16,esbuild0.28,@types/node26,@types/jest30,zod4.6@types/node26 no longer accepts aUint8Array<ArrayBufferLike>as aBlobPart, so multipart binary parts are copied into anArrayBuffer-backed view first. The e2e wire test still asserts the bytes arrive verbatim.--testPathPatternto--testPathPatterns(test:integrationscript).json-schema-ref-parser 16 requires Node.js ≥ 22.19.0 (Node 20 reached end-of-life in April 2026).
engines.nodeis now>=22.19.0, and the CI matrix drops 20.x.Verification
yarn buildtsc --noEmityarn test:coverage: 1050 tests, 100% statements/branches/functions/linesyarn test:unitandyarn test:integrationyarn test:e2e: 56 testsSummary by CodeRabbit
Security
Bug Fixes
Uint8Arrayvalues.Compatibility