GHSA-r745-8hwv-h473: Flowise: Unauthenticated OAuth2 Refresh Enables Non-Blind SSRF and Secret Exfiltration
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.
2. 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.
3. Non-blind response reflection
- Response returns:
- tokenInfo: { ...tokenData, ... }
- tokenData is the attacker/internal server response body.
4. 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
python3 -u - <<'PY'
from http.server import BaseHTTPRequestHandler, HTTPServer
import json
class H(BaseHTTPRequestHandler):
def do_POST(self):
l = int(self.headers.get('Content-Lengt
Details
Original advisory: https://github.com/advisories/GHSA-r745-8hwv-h473
Referenced CVEs
| CVE | CSIRTS overview | External |
|---|---|---|
| CVE-2026-69250 | coverage & exploitation status | NVD · CVE.org |
Same CVEs, other sources
How other CERTs, PSIRTs and databases cover the vulnerabilities in this advisory.
More from GitHub Security Advisories
- mediumGHSA-xm43-3m56-w3wf: Ghost: Paid gift memberships obtainable at minimal cost via the donations feature2026-08-04
- mediumGHSA-chgm-3698-jm42: Ghost: Member existence leak via magic link sign-in response2026-08-04
- highGHSA-xpp7-93x6-v29m: XSS in Ghost's ActivityPub client2026-08-04
- mediumGHSA-7mpp-r37j-x5wh: Ghost: Session Fixation in Ghost Admin2026-08-04
- mediumGHSA-cjc9-q5gf-327p: Ghost: Theme Upload Path Traversal2026-08-04