Fix: DNS rebinding TOCTOU in safeFetch (#405)#538
Fix: DNS rebinding TOCTOU in safeFetch (#405)#538advancedresearcharray wants to merge 3 commits into
Conversation
|
Hi @advancedresearcharray, DetailsInstructions for interacting with me using comments are available here. |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses a security vulnerability related to DNS rebinding in the Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request enhances SSRF protection and stream handling in safe-fetch.ts and ssrf-guard.ts. Specifically, it correctly formats pinned IPv6 hostnames with brackets, throws an error when DNS resolution fails to prevent TOCTOU vulnerabilities, and cancels the stream reader when the response size exceeds maxSize. The feedback suggests avoiding awaiting reader.cancel() to prevent blocking or delaying the 'response too large' error.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| if (done) break; | ||
| total += value.byteLength; | ||
| if (total > maxSize) { | ||
| await reader.cancel().catch(() => undefined); |
There was a problem hiding this comment.
Awaiting reader.cancel() here can block the execution and delay throwing the 'response too large' error (or even hang indefinitely if the stream's cancel promise hangs). Since we are already aborting the controller and throwing an error, we can trigger the cancellation in the background without awaiting it.
| await reader.cancel().catch(() => undefined); | |
| reader.cancel().catch(() => undefined); |
|
Addressed review feedback in 361dd9c: Verified locally: `vitest run test/ssrf-guard.test.ts test/safe-fetch.test.ts` — 97 tests pass. |
Do not await reader.cancel() when rejecting oversized streams; abort the fetch and throw immediately so a slow cancel cannot delay the error. Add regression test for bodies exactly at maxSize. Co-authored-by: Cursor <cursoragent@cursor.com>
…ai#405) Tighten SSRF guard regression tests to match the thrown error string when hostname lookup fails or returns no addresses. Co-authored-by: Cursor <cursoragent@cursor.com>
352d638 to
e9fdb0c
Compare
|
This PR is ready for merge. CI is green, and there are no outstanding review comments. |
|
This PR is ready to be merged! 🚀 Please review and merge when convenient. 😊 |
|
DNS rebinding TOCTOU fix is ready to merge. CI is green, and no further action required. |
|
PR looks good! Ready for merge. |
Summary
Closes #405.
assertNotPrivateHost: throwSSRF blocked: DNS resolution failedwhen hostname DNS lookup fails or returns no addresses, instead of returningnulland lettingnet.fetchre-resolve independently (DNS rebinding TOCTOU).safeFetch: fire-and-forgetreader.cancel()when streaming pastmaxSizeso a slow cancel cannot delay the error.Root cause
When the SSRF guard DNS lookup failed or returned no addresses,
assertNotPrivateHostreturnednull.safeFetchthen callednet.fetchwith the original hostname, which performs its own DNS resolution — reopening the TOCTOU window between the guard check and the actual fetch.Test plan
vitest run test/ssrf-guard.test.ts test/safe-fetch.test.ts— 97 tests pass