VDB
EN
HIGH 7.1

GHSA-2x8m-83vc-6wv4

Flowise: SSRF Protection Bypass (TOCTOU & Default Insecure)

상세

### Summary The core security wrappers (secureAxiosRequest and secureFetch) intended to prevent Server-Side Request Forgery (SSRF) contain multiple logic flaws. These flaws allow attackers to bypass the allow/deny lists via DNS Rebinding (Time-of-Check Time-of-Use) or by exploiting the default configuration which fails to enforce any deny list.

### Details The flaws exist in `packages/components/src/httpSecurity.ts`.

Default Insecure: If process.env.HTTP_DENY_LIST is undefined, checkDenyList returns immediately, allowing all requests (including localhost).

DNS Rebinding (TOCTOU): The function performs a DNS lookup (dns.lookup) to validate the IP, and then the HTTP client performs a new lookup to connect. An attacker can serve a valid IP first, then switch to an internal IP (e.g., `127.0.0.1`) for the second lookup.

### PoC Ensure `HTTP_DENY_LIST` is unset (default behavior).

Use any node utilizing secureFetch to access `http://127.0.0.1`.

Result: Request succeeds.

#### Scenario 2: DNS Rebinding

Attacker controls domain attacker.com and a custom DNS server.

Configure DNS to return `1.1.1.1` (Safe IP) with TTL=0 for the first query.

Configure DNS to return `127.0.0.1` (Blocked IP) for subsequent queries.

Flowise validates `attacker.com` -> `1.1.1.1` (Allowed).

Flowise fetches `attacker.com` -> `127.0.0.1` (Bypass).

Run the following for manual verification

```ts // PoC for httpSecurity.ts Bypasses import * as dns from 'dns/promises';

// Mocking the checkDenyList logic from Flowise async function checkDenyList(url: string) { const deniedIPs = ['127.0.0.1', '0.0.0.0']; // Simplified deny list logic

if (!process.env.HTTP_DENY_LIST) { console.log(\"⚠️ HTTP_DENY_LIST not set. Returning allowed.\"); return; // Vulnerability 1: Default Insecure }

const { hostname } = new URL(url); const { address } = await dns.lookup(hostname);

if (deniedIPs.includes(address)) { throw new Error(`IP ${address} is denied`); } console.log(`✅ IP ${address} allowed check.`); }

async function runPoC() { console.log(\"--- Test 1: Default Configuration (Unset HTTP_DENY_LIST) ---\"); // Ensure env var is unset delete process.env.HTTP_DENY_LIST; try { await checkDenyList('http://127.0.0.1'); console.log(\"[PASS] Default config allowed localhost access.\"); } catch (e) { console.log(\"[FAIL] Blocked:\", e.message); }

console.log(\"\ --- Test 2: 'private' Keyword Bypass (Logic Flaw) ---\"); process.env.HTTP_DENY_LIST = 'private'; // User expects this to block localhost try { await checkDenyList('http://127.0.0.1'); // In real Flowise code, 'private' is not expanded to IPs, so it only blocks the string \"private\" console.log(\"[PASS] 'private' keyword failed to block localhost (Mock simulation).\"); } catch (e) { console.log(\"[FAIL] Blocked:\", e.message); } }

runPoC(); ```

### Impact Confidentiality: High (Access to internal services if protection is bypassed).

Integrity: Low/Medium (If internal services allow state changes via GET).

Availability: Low.

이 버전이 영향받나요?

사용 중인 패키지 버전을 입력하면 즉시 평가합니다.

영향 패키지

npm / flowise
최초 영향 버전: 0 수정 버전: 3.1.0
수정 npm install flowise@3.1.0
npm / flowise-components
최초 영향 버전: 0 수정 버전: 3.1.0
수정 npm install flowise-components@3.1.0

참고