GHSA-c2c9-mfw7-p8hw: Flowise: cross-workspace chatflow config disclosure

GHSA-c2c9-mfw7-p8hw MEDIUM
Published May 20, 2026
CISO Take

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.

Sources: GitHub Advisory ATLAS

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.

Attack Kill Chain

Initial Access
Attacker obtains a valid Flowise API key for any workspace in the target instance, either by registering a free account or through credential theft.
AML.T0012
Exploitation
Attacker calls GET /api/v1/chatflows/apikey/<key> without the keyonly parameter, triggering a SQL query that ORs in all chatflows with no API key across every workspace.
AML.T0049
Collection
Full ChatFlow entities from all unprotected workspaces are returned, including system prompts, custom function code, internal URLs, model configs, and TTS/STT credential IDs.
AML.T0084
Impact
Attacker exfiltrates AI intellectual property and uses harvested credential IDs to abuse downstream TTS/STT services billed to victim organizations.
AML.T0048.004

What systems are affected?

Package Ecosystem Vulnerable Range Patched
flowise npm <= 3.1.1 3.1.2

Do you use flowise? You're affected.

Severity & Risk

CVSS 3.1
N/A
EPSS
N/A
Exploitation Status
No known exploitation
Sophistication
Trivial

What should I do?

5 steps
  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.

Classification

Compliance Impact

This CVE is relevant to:

EU AI Act
Art. 9 - Risk management system
ISO 42001
A.6.1 - AI system access control
NIST AI RMF
GOVERN 1.1 - Policies and processes for AI risk management
OWASP LLM Top 10
LLM07 - System Prompt Leakage

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.

Technical Details

NVD Description

## 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.

Timeline

Published
May 20, 2026
Last Modified
May 20, 2026
First Seen
May 20, 2026

Related Vulnerabilities