Typebot: Server-Side Request Forgery in the HTTP Request block via a redirect bypass of the SSRF allowlist

Typebot's HTTP Request block validates only the initially requested URL against the SSRF allowlist, because a per-call fetch overrides the validating fetch instance, so an attacker host with a 302/307 redirect points at internal addresses and AWS IMDSv1.

Advisory ID: TP-2026-052
Product: Typebot (open-source builder for chatbots and conversational forms, self-hosted)
Vulnerability type: Server-Side Request Forgery (CWE-918)
CVE: pending
CVSS 3.1: 7.7 (High) · CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
Vendor advisory: GHSA-gmm5-4r2j-mq64
Affected versions: Typebot <= 3.17.2
Fixed in: Typebot 3.18.0
Reported: 4 June 2026

Summary

Typebot is a self-hosted builder for chatbots and conversational forms whose HTTP Request (webhook) block runs server-side by default. The block is meant to be protected by safeKy, which re-validates every redirect hop against the SSRF allowlist and pins a DNS-rebind-safe dispatcher. The caller, however, passes its own unprotected fetch that overrides the validating fetch instance, so only the initially requested URL is checked and redirect targets are left unvalidated. A bot author points the block at an attacker host that passes the initial check and then redirects with a 302/307 to an internal, loopback or IMDSv1 target, with method, headers and body surviving the redirect. This makes internal services and the temporary AWS IAM credentials over IMDSv1 reachable. It is an incomplete fix of CVE-2025-64709.

Root cause

The block runs server-side by default (isExecutedOnClient=false, packages/blocks/integrations/src/httpRequest/constants.ts:21) and is meant to be protected by safeKy, whose fetch re-validates every redirect hop with redirect:"manual" plus validateHttpReqUrl(location) and pins a DNS-rebind-safe undici dispatcher (packages/lib/src/ky.ts:72/99/113). But executeHttpRequestBlock.ts:289-295 passes its own unprotected fetch (plain rebuildFetchWithoutChunkedEncoding with native fetch, redirect:"follow", no dispatcher) into safeKy(request.url, omit(request,"url")) (:312), and ky 1.2.4 overrides the instance default fetch with this fetch as a scalar, so the validating fetch never runs and only the initial URL is checked (:247). validateHttpReqHeaders (validateHttpReqUrl.ts:141, BLOCKED_HEADERS) still blocks the AWS, GCP and Azure metadata headers on the initial request, so IMDSv2, GCP and Azure stay mitigated, but AWS IMDSv1 with no header is reachable. The baseline attacker is any registered user (open signup is the default); the attack becomes anonymous when the author places a prefillable {{variable}} in the URL, headers or body, which runs through parseVariables (:180-228).

Proof of Concept

# The attacker host passes the initial check, then redirects internally:
#   https://attacker.example/redirect  ->  302 Location: http://172.16.0.10/…

# Anonymous chat start that triggers the HTTP Request block:
POST /api/v1/typebots/<publicId>/startChat
# The server follows the 302 to the internal target and returns its body to the caller.
# A 307 + POST carries method, JSON body and an X-Injected header to the internal target.

In the live verification on version 3.17.1 (ky 1.2.4), after an anonymous startChat the server followed a 302 to an internal-only service in the 172.16/12 range and returned its body to the unauthenticated caller (readable SSRF), while the same internal or link-local URL set directly was blocked (Access to link-local addresses (169.254.0.0/16) is not allowed, control run). A 307 with POST carried the method, a JSON body and a custom X-Injected header to the internal target, which demonstrates the write capability.

Impact

  • Readable SSRF from the server to internal, loopback and link-local services whose response is returned to the caller.
  • Access to AWS IMDSv1 and thereby to the instance's temporary IAM credentials (IMDSv2, GCP and Azure stay mitigated by the header block).
  • Through a 307 with POST, transfer of method, body and headers to internal targets, so state-changing requests rather than only a blind GET.
  • The baseline attacker is any registered user under the default open signup; anonymous as soon as a prefillable variable sits in the URL, headers or body.

References

Is Something Like This in Your Software?

Our team found this vulnerability in the course of its work. Have your applications tested by the same specialists, with a penetration test from turingpoint.