🐛 Fix SSRF redirect bypass in HTTP Request and Code blocks#2432
🐛 Fix SSRF redirect bypass in HTTP Request and Code blocks#2432baptisteArno merged 2 commits intomainfrom
Conversation
The HTTP Request block and Code block validated the initial URL but followed 302 redirects without re-validating, allowing redirect to internal IPs. Use safeKy (redirect:manual + re-validation) in both. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. 3 Skipped Deployments
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 221e05fa70
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| ); | ||
| const location = new URL( | ||
| response.headers.get("location")!, | ||
| request.url, |
There was a problem hiding this comment.
Resolve redirect Location against current response URL
The redirect loop builds each next URL with new URL(..., request.url), but request.url is always the original request. In a chained redirect where a later hop returns a relative Location (for example https://a.com -> https://b.com -> /final), this resolves /final against a.com instead of b.com, so the sandboxed fetch can call the wrong endpoint or fail unexpectedly. Use the current hop URL (e.g. response.url) as the base when resolving each redirect target.
Useful? React with 👍 / 👎.
| request.url, | ||
| ).toString(); | ||
| await validateHttpReqUrl(location); | ||
| response = await fetch(location, { ...init, redirect: "manual" }); |
There was a problem hiding this comment.
Preserve fetch redirect method semantics
Each redirect hop reuses the original init unchanged (fetch(location, { ...init, redirect: "manual" })), which changes behavior versus native fetch for 301/302/303 responses: POST/PUT requests should be converted to GET (with no body) on follow-up requests. With the current loop, redirected non-idempotent requests may be replayed with the original method/body, causing wrong side effects or request failures compared to prior behavior.
Useful? React with 👍 / 👎.
Summary
safeKyinstead ofky, and Code block's sandboxedfetchnow follows redirects manually withredirect: "manual"+ re-validation of eachLocationhop viavalidateHttpReqUrl.safeKy(not just indirect Location header checks), including chained redirect scenarios.nx-ignorenow exits early with code 0 whenVERCEL_ENV=preview.Test plan
bunx nx test @typebot.io/lib— 76 tests pass (0 fail, 6 skip)NODE_ENV=development bun test packages/lib/src/safeKy.test.ts— 8 tests pass (redirect bypass verified end-to-end)bunx nx typecheck @typebot.io/bot-engine— passesbunx nx typecheck @typebot.io/variables— passes🤖 Generated with Claude Code