Flowise's `/api/v1/chatflows/apikey/:apikey` endpoint fails to scope queries to the caller's workspace, meaning any authenticated user with a valid API key in one workspace can retrieve the full configuration — system prompts, custom code, internal URLs, and credential IDs — of chatflows belonging to every other workspace in the deployment. Because API key assignment is opt-in in Flowise, the vast majority of chatflows in a multi-tenant instance are exposed by default, amplifying the blast radius significantly. No public exploit is listed and EPSS data is unavailable, but the attack requires only a simple curl call with no special tooling, making it trivially reproducible by any tenant. Organizations running Flowise in multi-workspace or SaaS-style configurations should upgrade to 3.1.2 immediately; as a short-term workaround, assign an API key to every chatflow to remove them from the unscoped OR clause.
What is the risk?
Rated medium by the reporter, but operationally this is high-impact for multi-tenant Flowise deployments. Exploitability is trivial — a single unauthenticated-looking HTTP GET with a valid API key is all that is required, and the default behavior (omitting `keyonly`) triggers the vulnerable code path. The primary risk mitigant is that an attacker must already hold a valid API key in the target instance, narrowing the threat to insider threats, compromised accounts, or shared-instance scenarios. Given Flowise's 79 prior CVEs and its role as a no-code AI agent builder used by teams with limited security maturity, patching velocity may be slow across the installed base.
How does the attack unfold?
What systems are affected?
| Package | Ecosystem | Vulnerable Range | Patched |
|---|---|---|---|
| Flowise | npm | <= 3.1.1 | 3.1.2 |
Do you use Flowise? You're affected.
How severe is it?
What should I do?
5 steps-
Patch: Upgrade flowise to 3.1.2 which adds workspace-scoped filtering to the
getChatflowByApiKeyservice query. -
Workaround (if patching is blocked): Assign an explicit API key to every chatflow — this removes them from the
apikeyid IS NULLOR clause and breaks the cross-workspace leak. -
Audit: Review server-side access logs for requests to
/api/v1/chatflows/apikey/lacking the?keyonly=trueparameter, particularly from API keys belonging to low-privilege or external workspaces. -
Credential rotation: Any TTS/STT credential IDs stored in chatflow configs should be considered compromised and rotated if multi-workspace access existed prior to patching.
-
Network controls: Restrict the Flowise API port to internal networks or place an API gateway in front that enforces workspace-level JWT claims before proxying requests.
How is it classified?
Which compliance frameworks are affected?
This CVE is relevant to:
Frequently Asked Questions
What is GHSA-c2c9-mfw7-p8hw?
Flowise's `/api/v1/chatflows/apikey/:apikey` endpoint fails to scope queries to the caller's workspace, meaning any authenticated user with a valid API key in one workspace can retrieve the full configuration — system prompts, custom code, internal URLs, and credential IDs — of chatflows belonging to every other workspace in the deployment. Because API key assignment is opt-in in Flowise, the vast majority of chatflows in a multi-tenant instance are exposed by default, amplifying the blast radius significantly. No public exploit is listed and EPSS data is unavailable, but the attack requires only a simple curl call with no special tooling, making it trivially reproducible by any tenant. Organizations running Flowise in multi-workspace or SaaS-style configurations should upgrade to 3.1.2 immediately; as a short-term workaround, assign an API key to every chatflow to remove them from the unscoped OR clause.
Is GHSA-c2c9-mfw7-p8hw actively exploited?
No confirmed active exploitation of GHSA-c2c9-mfw7-p8hw has been reported, but organizations should still patch proactively.
How to fix GHSA-c2c9-mfw7-p8hw?
1. Patch: Upgrade flowise to 3.1.2 which adds workspace-scoped filtering to the `getChatflowByApiKey` service query. 2. Workaround (if patching is blocked): Assign an explicit API key to every chatflow — this removes them from the `apikeyid IS NULL` OR clause and breaks the cross-workspace leak. 3. Audit: Review server-side access logs for requests to `/api/v1/chatflows/apikey/` lacking the `?keyonly=true` parameter, particularly from API keys belonging to low-privilege or external workspaces. 4. Credential rotation: Any TTS/STT credential IDs stored in chatflow configs should be considered compromised and rotated if multi-workspace access existed prior to patching. 5. Network controls: Restrict the Flowise API port to internal networks or place an API gateway in front that enforces workspace-level JWT claims before proxying requests.
What systems are affected by GHSA-c2c9-mfw7-p8hw?
This vulnerability affects the following AI/ML architecture patterns: agent frameworks, no-code AI workflow builders, multi-tenant AI deployments, AI chatbot platforms.
What is the CVSS score for GHSA-c2c9-mfw7-p8hw?
No CVSS score has been assigned yet.
What is the AI security impact?
Affected AI Architectures
MITRE ATLAS Techniques
AML.T0012 Valid Accounts AML.T0048.004 AI Intellectual Property Theft AML.T0049 Exploit Public-Facing Application AML.T0083 Credentials from AI Agent Configuration AML.T0084 Discover AI Agent Configuration Compliance Controls Affected
What are the technical details?
Original Advisory
## Summary The `/api/v1/chatflows/apikey/:apikey` endpoint (whitelisted, accessible with API key auth only) returns all chatflows bound to the provided API key AND all chatflows across the entire system that have no API key assigned. This crosses workspace boundaries, allowing a user in Workspace A who has a valid API key to read the full configuration (including flowData, chatbotConfig, system prompts, and node configurations) of chatflows from Workspace B, Workspace C, and all other workspaces, as long as those chatflows have no API key assigned. ## Details The controller at `packages/server/src/controllers/chatflows/index.ts:90-107` validates the API key and calls the service: ```typescript const getChatflowByApiKey = async (req: Request, res: Response, next: NextFunction) => { try { const apikey = await apiKeyService.getApiKey(req.params.apikey) if (\!apikey) { return res.status(401).send("Unauthorized") } const apiResponse = await chatflowsService.getChatflowByApiKey(apikey.id, req.query.keyonly) return res.json(apiResponse) // Returns full chatflow objects with flowData } catch (error) { next(error) } } ``` The service at `packages/server/src/services/chatflows/index.ts:223-245` builds the database query: ```typescript const getChatflowByApiKey = async (apiKeyId: string, keyonly?: unknown): Promise<any> => { const appServer = getRunningExpressApp() let query = appServer.AppDataSource.getRepository(ChatFlow) .createQueryBuilder("cf") .where("cf.apikeyid = :apikeyid", { apikeyid: apiKeyId }) if (keyonly === undefined) { // When keyonly is not set (default), also return ALL chatflows with no API key query = query.orWhere("cf.apikeyid IS NULL").orWhere("cf.apikeyid = ''") } const dbResponse = await query.orderBy("cf.name", "ASC").getMany() return dbResponse // Returns full ChatFlow entities including flowData } ``` When `keyonly` is not provided as a query parameter (which is the default case), the query expands to include: - All chatflows bound to the provided API key (same workspace, expected behavior) - ALL chatflows with `apikeyid IS NULL` (any workspace, no workspace filter) - ALL chatflows with empty `apikeyid` (any workspace, no workspace filter) There is NO `workspaceId` filter in this query. The response includes the full `ChatFlow` entity, which contains: - `flowData` - the complete workflow graph including system prompts, model names, internal URLs, custom code - `chatbotConfig` - chatbot configuration including allowed origins - `apiConfig` - API configuration and override settings - `textToSpeech` / `speechToText` - TTS/STT configuration including credential IDs - `analytic` - analytics configuration ## PoC ```bash # Step 1: Attacker has a valid API key for Workspace A API_KEY="<attacker-workspace-a-api-key>" # Step 2: Query the chatflows/apikey endpoint WITHOUT keyonly parameter # Returns the attacker chatflows PLUS all chatflows without API keys from ALL workspaces curl -s "http://localhost:3000/api/v1/chatflows/apikey/" | jq ".[].workspaceId" # Step 3: With keyonly parameter, only chatflows bound to the API key are returned curl -s "http://localhost:3000/api/v1/chatflows/apikey/?keyonly=true" | jq ".[].workspaceId" ``` ## Impact - **Cross-Workspace Information Disclosure**: A user in any workspace can read the full configuration of chatflows from all other workspaces that do not have an API key assigned. This breaks workspace isolation. - **Intellectual Property Exposure**: System prompts, custom function code, and workflow architecture of chatflows from other workspaces/organizations are exposed. - **Credential Reference Leakage**: The `textToSpeech` and `speechToText` fields include credential IDs, which can be abused via the TTS generate endpoint. - **Amplified by Default**: Most chatflows are created without an API key assigned (API keys are opt-in), so the majority of chatflows in a multi-workspace deployment are affected. ## Recommended Fix Add workspace scoping to the `getChatflowByApiKey` query by passing the API key workspace ID and filtering the OR clause: ```typescript // packages/server/src/services/chatflows/index.ts const getChatflowByApiKey = async (apiKeyId: string, keyonly?: unknown, workspaceId?: string): Promise<any> => { const appServer = getRunningExpressApp() let query = appServer.AppDataSource.getRepository(ChatFlow) .createQueryBuilder("cf") .where("cf.apikeyid = :apikeyid", { apikeyid: apiKeyId }) if (keyonly === undefined && workspaceId) { // Only include unprotected chatflows from the SAME workspace query = query.orWhere( "(cf.apikeyid IS NULL OR cf.apikeyid = :empty) AND cf.workspaceId = :workspaceId", { empty: "", workspaceId } ) } const dbResponse = await query.orderBy("cf.name", "ASC").getMany() return dbResponse } ```
Exploitation Scenario
An adversary (a competitor, a disgruntled employee, or an attacker who phished an API key) authenticates to a shared Flowise instance with a low-privilege API key tied to Workspace A. They issue `GET /api/v1/chatflows/apikey/<their-key>` — no special parameters, just the default call. The TypeORM query executes `WHERE apikeyid = '<their-id>' OR apikeyid IS NULL OR apikeyid = ''` with no workspace filter, returning every chatflow across the entire platform that lacks an API key. The attacker iterates through the response, extracting `flowData` JSON blobs that contain GPT-4 system prompts encoding proprietary business logic, internal API endpoint URLs, hardcoded credentials passed as node parameters, and TTS credential IDs. They then replay those credential IDs against the `/api/v1/chatflows/<id>/tts` endpoint to verify access. Total time from API key to full intellectual property dump: under five minutes.
Weaknesses (CWE)
CWE-863 — Incorrect Authorization: The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check.
- [Architecture and Design] Divide the product into anonymous, normal, privileged, and administrative areas. Reduce the attack surface by carefully mapping roles with data and functionality. Use role-based access control (RBAC) [REF-229] to enforce the roles at the appropriate boundaries. Note that this approach may not protect against horizontal authorization, i.e., it will not protect a user from attacking others with the same role.
- [Architecture and Design] Ensure that access control checks are performed related to the business logic. These checks may be different than the access control checks that are applied to more generic resources such as files, connections, processes, memory, and database records. For example, a database may restrict access for medical records to a specific database user, but each record might only be intended to be accessible to the patient and the patient's doctor [REF-7].
Source: MITRE CWE corpus.
References
Timeline
Related Vulnerabilities
CVE-2025-71338 10.0 Flowise: unauthenticated file write enables RCE
Same package: flowise CVE-2025-59528 10.0 Flowise: Unauthenticated RCE via MCP config injection
Same package: flowise CVE-2025-61913 9.9 Flowise: path traversal in file tools leads to RCE
Same package: flowise CVE-2026-40933 9.9 Flowise: RCE via MCP stdio command injection
Same package: flowise CVE-2026-46442 9.9 Flowise: sandbox escape enables authenticated RCE
Same package: flowise