Release Notes
Patch Changes
25a64f8: Remove deprecated experimental generateImage exports.
375fdd7: fix: harden download URL SSRF guard against hostname and redirect bypasses
validateDownloadUrland the file download helpers (downloadBlob,download) could be bypassed in several ways when handling untrusted URLs:- A fully-qualified hostname with a trailing dot (e.g.
localhost.,myhost.local.) skipped the localhost/.localblocklist. - IPv6 addresses that embed an IPv4 address in their last 32 bits — IPv4-compatible (
::127.0.0.1), IPv4-translated (::ffff:0:127.0.0.1), and NAT64 (64:ff9b::127.0.0.1, including the64:ff9b:1::/48local-use prefix) — were not decoded and checked against the private IPv4 ranges. - Redirects were validated only after
fetchhad already followed them, so the request to a redirect target (e.g. an internal/metadata address) had already been issued before the check ran. - Several reserved/internal address ranges were not blocked: CGNAT (
100.64.0.0/10, used by some cloud providers for internal traffic), benchmarking (198.18.0.0/15), IETF protocol assignments (192.0.0.0/24), the reserved240.0.0.0/4block (including the255.255.255.255broadcast address), and IPv6 site-local (fec0::/10) and multicast (ff00::/8).
The validator now strips trailing dots before the hostname checks and fully expands IPv6 addresses to detect embedded private IPv4 targets. The download helpers now follow redirects manually (
redirect: 'manual'), re-validating each hop before requesting it, so an unsafe redirect target is never fetched. When a redirect cannot be inspected because the runtime returns an opaque response, the helpers fail closed (reject the redirect) on the server; only in a real browser — where SSRF is not reachable (fetch is constrained by CORS and cannot reach a server's internal network or cloud-metadata endpoints) — is the redirect followed natively so legitimate redirected downloads keep working.- A fully-qualified hostname with a trailing dot (e.g.
f18b08f: fix: redact server error details from UI message streams by default
toUIMessageStream,createUIMessageStream, andtoUIMessageChunkdefaulted theironErrorcallback togetErrorMessage, which serializes the raw error (error.toString()/JSON.stringify(error)) into the client-facing{ type: 'error', errorText }chunk — and also intotool-output-errorparts. The documented default was() => 'An error occurred.', so applications relying on the documented behavior were unknowingly streaming server exception details (internal hostnames, paths, provider request data, validation inputs) to end users.The default
onErrornow returns the documented generic'An error occurred.'. Raw error details are only emitted when the developer explicitly supplies anonErrorhandler. This also redactstool-output-errorand invalid-tool-input error text by default; pass anonErrorto surface richer messages.b4507d5: fix(provider-utils): cancel response body on download rejection to prevent socket leak
When a download was rejected early — because the
Content-Lengthheader exceeded the size limit, the response status was not ok, or a redirect resolved to a blocked URL — the fetch response body was left unconsumed and uncancelled. With WHATWG Fetch/undici this leaves the underlying TCP socket open instead of returning it to the connection pool, allowing an attacker-controlled origin to exhaust file descriptors and cause a denial of service. The body is now cancelled on all early-rejection paths inreadResponseWithSizeLimit,download, anddownloadBlob, andfetchWithValidatedRedirectscancels each redirect hop's body before following or rejecting the next hop.Updated dependencies [8c17bf8]
Updated dependencies [aeda373]
Updated dependencies [558777f]
Updated dependencies [375fdd7]
Updated dependencies [b4507d5]
- @ai-sdk/[email protected]
- @ai-sdk/[email protected]