Skip to content

🐛 Fix SSRF redirect bypass in HTTP Request and Code blocks#2432

Merged
baptisteArno merged 2 commits intomainfrom
baptisteArno/check-ssrf-fix
Apr 7, 2026
Merged

🐛 Fix SSRF redirect bypass in HTTP Request and Code blocks#2432
baptisteArno merged 2 commits intomainfrom
baptisteArno/check-ssrf-fix

Conversation

@baptisteArno
Copy link
Copy Markdown
Owner

Summary

  • Fix SSRF via open redirect bypass (GHSA-jxv3-m939-w95c): HTTP Request block now uses safeKy instead of ky, and Code block's sandboxed fetch now follows redirects manually with redirect: "manual" + re-validation of each Location hop via validateHttpReqUrl.
  • Improved safeKy tests: redirect bypass tests now run end-to-end through safeKy (not just indirect Location header checks), including chained redirect scenarios.
  • Skip Vercel preview builds: nx-ignore now exits early with code 0 when VERCEL_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 — passes
  • bunx nx typecheck @typebot.io/variables — passes

🤖 Generated with Claude Code

baptisteArno and others added 2 commits April 7, 2026 16:39
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>
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 7, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

3 Skipped Deployments
Project Deployment Actions Updated (UTC)
builder-v2 Ignored Ignored Apr 7, 2026 2:41pm
landing-page-v2 Ignored Ignored Apr 7, 2026 2:41pm
viewer-v2 Ignored Ignored Apr 7, 2026 2:41pm

Request Review

@baptisteArno baptisteArno merged commit 23818bb into main Apr 7, 2026
9 checks passed
@baptisteArno baptisteArno deleted the baptisteArno/check-ssrf-fix branch April 7, 2026 14:41
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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" });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant