A rejected download is supposed to be the safe path. In Vercel's AI SDK it was the attack path. The same pattern is sitting unpatched in most frameworks that fetch external content.
Here is the part that should worry you: the bug fired on the rejection path. Not when a download succeeded, but when the agent runtime correctly decided not to download something. Too big, wrong status, redirect to a blocked URL. The framework did the right thing, refused the fetch, and then leaked a TCP socket anyway.
Vercel shipped the fix on June 16 in two parallel releases, ai@6.0.207 and ai@5.0.204. The description is plain: when a download was rejected early, the fetch response body was "left unconsumed and uncancelled," which under standard Fetch implementations "leaves the underlying TCP socket open instead of returning it to the connection pool." An attacker who controls the origin you fetch from can keep tripping that rejection path, leak socket after socket, and exhaust the file descriptors on the host until the agent stops accepting connections.
That is a denial of service. No exploit chain, no memory corruption, no special privilege. Just a malicious server and an agent that politely refuses its oversized payloads.
The reason this matters beyond Vercel is uncomfortable. Fetching remote content is not an edge feature of agent runtimes. It is a core capability. Every agent that reads a URL, pulls a tool result, or follows a link runs this code path. Vercel found it and fixed it. The silence everywhere else is the story.
The rejection path is the attack surface nobody audits
Apply the Trust Boundary Model to an agent that fetches a URL. Data crosses from an untrusted remote origin into your runtime. You inspect at that boundary: is the response too large, is the status OK, did the redirect land somewhere it shouldn't. Those checks are the whole point. They are also exactly where the leak lived.
The Vercel fix names three rejection conditions: a Content-Length header that exceeds the size limit, a response status that is not OK, and a redirect that resolves to a blocked URL. All three are defensive outcomes. The runtime is protecting you. And in each case, the older code rejected the download without consuming or cancelling the response body.
With WHATWG Fetch and undici, an unconsumed body does not free the connection. It holds the socket open, out of the pool, indefinitely. The connection that should have been recycled is now a dead weight on the host's file descriptor table.
Here is why it is invisible: security review concentrates on the success path. What happens when the malicious file actually downloads? Can it escape the sandbox, poison context, trigger a tool? Reviewers stress-test the yes branch. The no branch, where the runtime correctly says "I won't fetch this," reads as the safe one. It got less scrutiny precisely because it looked like the defense.
The attacker reads the same code and sees the opposite. The cheapest way to hurt the host is not to get a payload through. It is to get reliably rejected thousands of times, each rejection leaking one more socket. Defense became the denial-of-service primitive.
Why an attacker-controlled origin is the realistic threat model
The phrase that should stop you in the Vercel notes is "attacker-controlled origin." The SDK release spells out that this lets such an origin "exhaust file descriptors and cause a denial of service." That is not a hypothetical lab condition. It is the normal operating environment of an agent.
Think about what your agent fetches. A URL a user pasted. A link inside a document it was asked to summarize. A tool that returns a resource location. A web page in a research task. In every one of those flows, the server on the other end is not yours. You do not control its headers, its status codes, or where its redirects point.
So the attacker does not need to breach your infrastructure. They need to get your agent to fetch a URL they control, which is the entire premise of an agent that browses, retrieves, and acts on the open web. Then they configure that origin to trip the rejection path on purpose. Send a Content-Length over the limit. Return a non-OK status. Redirect to something the runtime will block. Each refused request, under the unpatched code, costs the host one socket.
Apply Attack Surface Analysis. Enumerate the interfaces an agent exposes to the outside. The outbound fetch is one of the largest and least examined. We obsess over what comes in through that channel. We rarely ask what the channel itself costs when abused. File descriptors are a finite resource on every host. A leak that compounds on every rejection turns a finite resource into a countdown.
The deployment posture matters here. A copilot fetching the occasional link an engineer pastes is low-exposure. An autonomous agent crawling URLs unattended, on a long-lived host, is the Autonomy Spectrum failure mode in miniature: the more independent the agent, the more rejected fetches it generates without a human noticing the host slowly running out of descriptors.
Two release lines, same fix, on the same day
Vercel did not patch this once. It patched it twice, simultaneously, across two major version lines. The 6.0.207 release and the 5.0.204 release carry the identical fix description, down to the wording: cancel the response body on all early-rejection paths.
That is a tell worth reading. Backporting the same security fix to two live major versions on the same day, June 16, says the vendor considered the older line still in heavy production use and worth protecting. You do not spend the engineering effort to dual-patch a flaw you think is cosmetic. The breadth of the backport is the severity signal.
It also tells you something about who is exposed. If teams on the 5.x line still needed the patch, then a meaningful population of deployed agents was running the vulnerable code right up until this release. The fix existing does not mean the fix is applied. Patched upstream and patched in your running agent are different states, and the gap between them is where the denial of service lives.
The practical takeaway is blunt. If your stack uses Vercel's AI SDK, on either the 5.x or 6.x line, check your version. The leak is silent until it isn't. There is no error in your logs that says "socket leaked." There is only a host that eventually stops answering, and a postmortem that takes far longer than the upgrade would have.
The body-cancellation bug is a class, not an incident
This is the part the vendor notes cannot say and the angle insists on. The Vercel fix describes a behavior of "WHATWG Fetch/undici," not a quirk unique to Vercel's code. That detail generalizes the problem.
The underlying contract is the same everywhere: under standard Fetch semantics, if you receive a response and decide not to read it, you are obligated to cancel the body so the connection returns to the pool. Forget that, and the socket stays open. This is not Vercel's mistake to own alone. It is a footgun built into the most widely used HTTP-fetching primitive in the JavaScript ecosystem, which is the ecosystem a large share of agent runtimes are built on.
That means the precondition for this bug exists in any framework that does three things: fetches remote content, validates it before consuming it, and rejects on validation failure. Those three behaviors describe responsible network I/O. They also describe the exact shape of the leak. The frameworks doing the right thing, validating before reading, are structurally the most exposed, because validation creates the early-rejection path where the body goes unconsumed.
No other framework in the current source pack has published an equivalent fix. By analysis, that silence reads two ways and only one is good. Either their fetch code already cancels bodies on rejection, in which case fine. Or the bug is present and unreported, which the pattern of how this surfaced (one vendor noticing, quietly patching) makes the more likely default. Reports of a category-wide flaw usually start with exactly one vendor's release notes.
The Molt Cycle frames where agent frameworks sit right now: rapid growth into a security-crisis phase, the period where the foundational plumbing gets its first real adversarial scrutiny. Socket lifecycle on the rejection path is precisely the kind of unglamorous plumbing that survives the growth phase unexamined and gets found during hardening.
Connection-handling bugs are everywhere in this week's releases
Look across the same window of releases and a theme emerges that supports the structural reading. The flaws clustering in agent infrastructure right now are not model bugs. They are connection-lifecycle bugs.
Anthropic's Claude Code v2.1.179 shipped a fix for "mid-stream connection drops," where partial responses now get preserved instead of surfacing a raw error and the UI no longer hangs at "running tool." Different symptom, same family: what happens to an in-flight connection when something goes wrong.
E2B's sandbox SDK did the same kind of work, raising "a typed, actionable error when the sandbox dies while a request is in flight" across streaming calls, and its Python SDK mapped transport-level read timeouts to proper timeout exceptions. Again: the failure path of a network connection, getting hardened.
None of these is the Vercel socket leak. The point is the cluster. Multiple independent agent-infrastructure projects spent this release cycle fixing how connections behave when they fail, drop, or time out. That is what the early-but-maturing stage of a category looks like under the Molt Cycle: the happy path was built first and fast, and now the unhappy paths are getting their reckoning.
The Vercel leak is the most severe member of this family because its unhappy path is remotely triggerable and resource-exhausting. A dropped connection annoys a user. A leaked socket on every rejection lets a remote attacker take the host down. Same category of oversight, very different blast radius.
What to actually do, in order
Problem, agitated, now the solution. The problem: agent runtimes that fetch remote content can leak sockets on the rejection path. The cost: a remote attacker exhausts your host's file descriptors and your agent goes dark, with no obvious error pointing at the cause. The fix is mostly version hygiene plus a few defensive habits.
- Check your AI SDK version. If you run Vercel's AI SDK, upgrade to 6.0.207 on the 6.x line or 5.0.204 on the 5.x line. These are the releases that cancel the body on rejection. Do this first.
- Audit any other framework that fetches URLs. Ask one question of your stack: when a download is rejected for being too large, having a bad status, or redirecting somewhere blocked, does it cancel the response body? If nobody on your team knows, assume it doesn't.
- Cap outbound concurrency and set descriptor limits. A bounded connection pool and an OS-level file-descriptor limit turn "host goes dark silently" into "requests start failing loudly," which is a far better failure mode to debug. This is the Swiss Cheese Model: the patch is one layer, resource limits are a second, monitoring is a third.
- Watch the descriptor count, not just CPU and memory. Open file descriptors on agent hosts are the metric that goes wrong here, and almost nobody alerts on it. A slow upward creep with no corresponding workload increase is the leak's signature.
- Treat every fetched origin as hostile by default. Your agent does not control the servers it talks to. Configure timeouts, size limits, and redirect policies as if the origin is trying to hurt you, because the realistic threat model says it might be.
Patch the SDK now. Then go find out whether the rest of your stack has the same bug nobody has reported yet.
/Figures
- Jun 16, 18:36E2B SDK 2.30.1 / python-sdk 2.29.1
Typed errors for sandbox death mid-request; transport timeouts mapped to proper exceptions.
- Jun 16, 20:22Claude Code v2.1.179
Mid-stream connection drops now preserve partial responses instead of raw errors.
- Jun 16, 22:04Vercel ai@5.0.204
Cancel response body on download rejection to prevent socket leak (5.x line).
- Jun 16, 22:06Vercel ai@6.0.207
Same socket-leak fix backported to the 6.x line on the same day.
/Sources
/Key Takeaways
- Vercel's AI SDK leaked a TCP socket every time it rejected a download (too large, bad status, or blocked redirect), letting a malicious origin exhaust host file descriptors and cause a DoS.
- The fix shipped June 16 on two version lines at once (ai@6.0.207 and ai@5.0.204); dual-backporting a security fix the same day signals real severity and broad exposure.
- This is a Fetch/undici-level footgun, not a Vercel-specific mistake. Any framework that validates remote content before consuming it can leak sockets on the rejection path.
- Multiple agent-infra projects this cycle (Claude Code, E2B) hardened connection-failure handling. The pattern is a category in its security-crisis phase, not an isolated bug.
- Patch the SDK, audit other URL-fetching frameworks for body cancellation on rejection, set descriptor limits, and alert on open-file-descriptor creep.

