Skip to content

fix(security): validate redirect targets in download functions to prevent SSRF bypass#13111

Merged
gr2m merged 2 commits intomainfrom
fix/ssrf-redirect-bypass
Mar 5, 2026
Merged

fix(security): validate redirect targets in download functions to prevent SSRF bypass#13111
gr2m merged 2 commits intomainfrom
fix/ssrf-redirect-bypass

Conversation

@gr2m
Copy link
Copy Markdown
Collaborator

@gr2m gr2m commented Mar 5, 2026

Background

The existing validateDownloadUrl (added in #13085) only validates the initial URL before fetch(). Since fetch() follows HTTP redirects by default, an attacker can bypass SSRF protections by providing a safe-looking public URL that 302-redirects to internal endpoints (e.g., http://169.254.169.254/latest/meta-data/), enabling in-band response body exfiltration through the AI model's response.

Summary

Added response.redirected check with validateDownloadUrl(response.url) in both downloadBlob (@ai-sdk/provider-utils) and download (ai) functions to validate the final URL after following redirects, before reading the response body.

Manual Verification

  • pnpm vitest run packages/provider-utils/src/download-blob.test.ts — 16 tests pass
  • pnpm vitest run packages/provider-utils/src/validate-download-url.test.ts — 29 tests pass
  • pnpm vitest run packages/ai/src/util/download/download.test.ts -t "SSRF" — 5 tests pass

Checklist

  • Tests have been added / updated (for bug fixes / features)
  • Documentation has been added / updated (for bug fixes / features)
  • A patch changeset for relevant packages has been added (for bug fixes / features - run pnpm changeset in the project root)
  • I have reviewed this pull request (self-review)

Future Work

  • DNS rebinding protection could be added if a DNS resolution API becomes available in edge runtimes

…vent SSRF bypass

The existing `validateDownloadUrl` only validates the initial URL, but
`fetch()` follows redirects by default. An attacker can provide a
safe-looking public URL that redirects to internal endpoints like
`http://169.254.169.254/latest/meta-data/`, bypassing SSRF protections.

Added `response.redirected` check with `validateDownloadUrl(response.url)`
in both `downloadBlob` and `download` functions to validate the final URL
after following redirects, before reading the response body.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@tigent tigent bot added ai/provider related to a provider package. Must be assigned together with at least one `provider/*` label bug Something isn't working as documented reproduction provided labels Mar 5, 2026
@gr2m gr2m added backport Admins only: add this label to a pull request in order to backport it to the prior version ai/core core functions like generateText, streamText, etc. Provider utils, and provider spec. and removed ai/provider related to a provider package. Must be assigned together with at least one `provider/*` label labels Mar 5, 2026
@gr2m gr2m marked this pull request as ready for review March 5, 2026 17:41
…load tests

MSW was not intercepting fetch() calls, causing 2 tests to fail against
the real http://example.com. Switched to globalThis.fetch mocking to
match the pattern used in download-blob.test.ts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gr2m gr2m merged commit 531251e into main Mar 5, 2026
18 checks passed
@gr2m gr2m deleted the fix/ssrf-redirect-bypass branch March 5, 2026 20:21
vercel-ai-sdk bot pushed a commit that referenced this pull request Mar 5, 2026
…vent SSRF bypass (#13111)

## Background

The existing `validateDownloadUrl` (added in #13085) only validates the
initial URL before `fetch()`. Since `fetch()` follows HTTP redirects by
default, an attacker can bypass SSRF protections by providing a
safe-looking public URL that 302-redirects to internal endpoints (e.g.,
`http://169.254.169.254/latest/meta-data/`), enabling in-band response
body exfiltration through the AI model's response.

## Summary

Added `response.redirected` check with
`validateDownloadUrl(response.url)` in both `downloadBlob`
(`@ai-sdk/provider-utils`) and `download` (`ai`) functions to validate
the final URL after following redirects, before reading the response
body.

## Manual Verification

- `pnpm vitest run packages/provider-utils/src/download-blob.test.ts` —
16 tests pass
- `pnpm vitest run
packages/provider-utils/src/validate-download-url.test.ts` — 29 tests
pass
- `pnpm vitest run packages/ai/src/util/download/download.test.ts -t
"SSRF"` — 5 tests pass
@vercel-ai-sdk vercel-ai-sdk bot removed the backport Admins only: add this label to a pull request in order to backport it to the prior version label Mar 5, 2026
@vercel-ai-sdk
Copy link
Copy Markdown
Contributor

vercel-ai-sdk bot commented Mar 5, 2026

✅ Backport PR created: #13127

vercel-ai-sdk bot added a commit that referenced this pull request Mar 5, 2026
…ons to prevent SSRF bypass (#13127)

This is an automated backport of #13111 to the release-v6.0 branch. FYI
@gr2m

Co-authored-by: Gregor Martynus <39992+gr2m@users.noreply.github.com>
@vercel-ai-sdk
Copy link
Copy Markdown
Contributor

vercel-ai-sdk bot commented Mar 5, 2026

🚀 Published in:

Package Version
ai 7.0.0-beta.3
@ai-sdk/alibaba 2.0.0-beta.1
@ai-sdk/amazon-bedrock 5.0.0-beta.1
@ai-sdk/angular 3.0.0-beta.3
@ai-sdk/anthropic 4.0.0-beta.1
@ai-sdk/assemblyai 3.0.0-beta.1
@ai-sdk/azure 4.0.0-beta.2
@ai-sdk/baseten 2.0.0-beta.1
@ai-sdk/black-forest-labs 2.0.0-beta.1
@ai-sdk/bytedance 2.0.0-beta.1
@ai-sdk/cerebras 3.0.0-beta.1
@ai-sdk/cohere 4.0.0-beta.1
@ai-sdk/deepgram 3.0.0-beta.1
@ai-sdk/deepinfra 3.0.0-beta.1
@ai-sdk/deepseek 3.0.0-beta.1
@ai-sdk/elevenlabs 3.0.0-beta.1
@ai-sdk/fal 3.0.0-beta.1
@ai-sdk/fireworks 3.0.0-beta.1
@ai-sdk/gateway 4.0.0-beta.2
@ai-sdk/gladia 3.0.0-beta.1
@ai-sdk/google 4.0.0-beta.3
@ai-sdk/google-vertex 5.0.0-beta.3
@ai-sdk/groq 4.0.0-beta.1
@ai-sdk/huggingface 2.0.0-beta.1
@ai-sdk/hume 3.0.0-beta.1
@ai-sdk/klingai 4.0.0-beta.1
@ai-sdk/langchain 3.0.0-beta.3
@ai-sdk/llamaindex 3.0.0-beta.3
@ai-sdk/lmnt 3.0.0-beta.1
@ai-sdk/luma 3.0.0-beta.1
@ai-sdk/mcp 2.0.0-beta.1
@ai-sdk/mistral 4.0.0-beta.1
@ai-sdk/moonshotai 3.0.0-beta.1
@ai-sdk/open-responses 2.0.0-beta.1
@ai-sdk/openai 4.0.0-beta.2
@ai-sdk/openai-compatible 3.0.0-beta.1
@ai-sdk/perplexity 4.0.0-beta.1
@ai-sdk/prodia 2.0.0-beta.1
@ai-sdk/provider-utils 5.0.0-beta.1
@ai-sdk/react 4.0.0-beta.3
@ai-sdk/replicate 3.0.0-beta.1
@ai-sdk/revai 3.0.0-beta.1
@ai-sdk/rsc 3.0.0-beta.3
@ai-sdk/svelte 5.0.0-beta.3
@ai-sdk/togetherai 3.0.0-beta.1
@ai-sdk/valibot 3.0.0-beta.1
@ai-sdk/vercel 3.0.0-beta.1
@ai-sdk/vue 4.0.0-beta.3
@ai-sdk/xai 4.0.0-beta.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai/core core functions like generateText, streamText, etc. Provider utils, and provider spec. bug Something isn't working as documented reproduction provided

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant