GHSA-8gj2-2cvc-6xx7: Flowise Unauthenticated Credential Abuse Vulnerability
MODERATEGHSA-8gj2-2cvc-6xx7 is a MODERATE unauthenticated credential abuse vulnerability (CWE-862: Missing Authorization) affecting Flowise libraries in the npm ecosystem. The issue involves unauthenticated credential abuse via text-to-speech endpoint allows unauthorized use of private chatflow tts credentials. Remediation is available by upgrading affected packages to version 3.1.4.
GHSA-8gj2-2cvc-6xx7 at a Glance
How to Fix GHSA-8gj2-2cvc-6xx7
To remediate this vulnerability, upgrade all affected Flowise dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
npm install flowise@3.1.4
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
npm ls flowise
How to Check if You Are Affected
To determine whether your Node.js application is affected by GHSA-8gj2-2cvc-6xx7, inspect your project dependencies using npm:
npm ls flowise
Analyze the terminal output to locate any version of Flowise in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 3.1.4), your application is affected.
Note: The npm ls flowise command inspects dependencies declared in your package.json and lockfile; it does not perform automated runtime dynamic scanning.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-862: Missing Authorization, where the product does not perform an authorization check when an actor attempts to access a resource or perform an action. In Flowise, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
GHSA-8gj2-2cvc-6xx7 Affected Flowise Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
flowise
|
npm |
< 3.1.4
|
3.1.4
|
References
Frequently Asked Questions
What is GHSA-8gj2-2cvc-6xx7?
Which Flowise versions are affected?
What version fixes GHSA-8gj2-2cvc-6xx7?
Is flowise affected?
What CWE is associated with GHSA-8gj2-2cvc-6xx7?
How can I check npm dependencies for GHSA-8gj2-2cvc-6xx7?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-8gj2-2cvc-6xx7",
"modified" : "2026-08-04T19:19:44Z",
"published" : "2026-08-04T19:19:44Z",
"aliases" : [ ],
"summary" : "Flowise: Unauthenticated Credential Abuse via Text-to-Speech Endpoint Allows Unauthorized Use of Private Chatflow TTS Credentials",
"details" : "## Summary\n\nThe `/api/v1/text-to-speech/generate` endpoint is whitelisted (requires no authentication) and accepts any `chatflowId` without checking whether the referenced chatflow is public. An unauthenticated attacker who knows a valid chatflow UUID can abuse that chatflow's TTS credential (OpenAI or ElevenLabs API key) to generate unlimited text-to-speech audio, incurring costs on the chatflow owner's account.\n\n## Details\n\nThe TTS `generateTextToSpeech` controller at `packages/server/src/controllers/text-to-speech/index.ts:10-171` is whitelisted at `packages/server/src/utils/constants.ts:41`:\n\n```typescript\n'/api/v1/text-to-speech/generate',\n```\n\nWhen a `chatflowId` is provided and the user is not authenticated (no `req.user`), the controller falls back to fetching the chatflow without workspace scoping:\n\n```typescript\n// packages/server/src/controllers/text-to-speech/index.ts:36-42\nif (workspaceId) {\n chatflow = await chatflowsService.getChatflowById(chatflowId, workspaceId)\n} else {\n // Fallback: get workspaceId from chatflow when req.user.activeWorkspaceId is not set\n chatflow = await chatflowsService.getChatflowById(chatflowId) // NO isPublic check\n workspaceId = chatflow.workspaceId\n}\n```\n\nThe `getChatflowById` function at `packages/server/src/services/chatflows/index.ts:247-272` fetches any chatflow by ID when `workspaceId` is not provided:\n\n```typescript\nconst dbResponse = await appServer.AppDataSource.getRepository(ChatFlow).findOne({\n where: {\n id: chatflowId,\n ...(workspaceId ? { workspaceId } : {}) // No workspace filter when workspaceId is undefined\n }\n})\n```\n\nThe controller then extracts the TTS provider configuration from the chatflow:\n\n```typescript\n// packages/server/src/controllers/text-to-speech/index.ts:51-66\nconst ttsConfig = JSON.parse(chatflow.textToSpeech)\nconst activeProviderKey = Object.keys(ttsConfig).find(key => ttsConfig[key].status === true)\nconst providerConfig = ttsConfig[activeProviderKey]\nprovider = activeProviderKey\ncredentialId = providerConfig.credentialId // Extracted from private chatflow\n```\n\nThis `credentialId` is then used to decrypt and use the stored credential (OpenAI or ElevenLabs API key) to make TTS API calls at `packages/components/src/textToSpeech.ts:33-34`:\n\n```typescript\nconst credentialId = textToSpeechConfig.credentialId as string\nconst credentialData = await getCredentialData(credentialId ?? '', options)\n```\n\n## PoC\n\n```bash\n# Step 1: Know a chatflow UUID that has TTS enabled (any chatflow, public or private)\nCHATFLOW_ID=\"<any-chatflow-uuid-with-tts-enabled>\"\n\n# Step 2: Abuse the TTS credential to generate audio without authentication\ncurl -X POST \"http://localhost:3000/api/v1/text-to-speech/generate\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"chatflowId\": \"'${CHATFLOW_ID}'\",\n \"chatId\": \"attacker-chat-1\",\n \"chatMessageId\": \"msg-1\",\n \"text\": \"This is a test of unauthorized TTS generation using someone elses API key\"\n }'\n\n# Expected: Returns SSE stream with TTS audio data using the chatflow owner's OpenAI/ElevenLabs credentials\n# event: tts_start\n# data: {\"event\":\"tts_start\",\"data\":{\"chatMessageId\":\"msg-1\",\"format\":\"mp3\"}}\n# event: tts_data\n# data: {\"event\":\"tts_data\",\"data\":{\"chatMessageId\":\"msg-1\",\"audioChunk\":\"<base64-audio>\"}}\n\n# Step 3: Repeat with large text to incur costs\ncurl -X POST \"http://localhost:3000/api/v1/text-to-speech/generate\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"chatflowId\": \"'${CHATFLOW_ID}'\",\n \"chatId\": \"attacker-chat-2\",\n \"chatMessageId\": \"msg-2\",\n \"text\": \"'$(python3 -c \"print('A' * 4096)\")'\"\n }'\n```\n\n## Impact\n\n- **Financial Impact**: An attacker can generate unlimited TTS audio using the chatflow owner's OpenAI or ElevenLabs API credentials, incurring potentially significant costs. OpenAI TTS costs ~$15/1M characters; an attacker could generate large volumes of audio.\n- **Credential Abuse**: The attacker effectively gains indirect access to the stored API credentials without needing to authenticate or have any permissions. The credentials are not directly exposed but are used on behalf of the attacker.\n- **Denial of Service**: By exhausting the API quota/budget of the credential, the attacker can deny service to legitimate users of the chatflow.\n- **Affects Private Chatflows**: This vulnerability affects all chatflows with TTS configured, including those explicitly marked as private (`isPublic: false`).\n\n## Recommended Fix\n\n1. Check `isPublic` before allowing unauthenticated TTS generation:\n\n```typescript\n// packages/server/src/controllers/text-to-speech/index.ts\nif (chatflowId) {\n let chatflow;\n let workspaceId = req.user?.activeWorkspaceId;\n \n if (workspaceId) {\n chatflow = await chatflowsService.getChatflowById(chatflowId, workspaceId)\n } else {\n chatflow = await chatflowsService.getChatflowById(chatflowId)\n // Verify the chatflow is public before using its credentials\n if (!chatflow.isPublic) {\n throw new InternalFlowiseError(\n StatusCodes.UNAUTHORIZED,\n 'TTS generation requires authentication for non-public chatflows'\n )\n }\n workspaceId = chatflow.workspaceId\n }\n // ... rest of the function\n}\n```\n\n2. Consider applying rate limiting to the TTS endpoint to prevent abuse even for public chatflows.",
"severity" : [ {
"type" : "CVSS_V4",
"score" : "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:L/SC:N/SI:N/SA:N"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "npm",
"name" : "flowise"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"fixed" : "3.1.4"
} ]
} ],
"database_specific" : {
"last_known_affected_version_range" : "<= 3.1.3"
}
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-8gj2-2cvc-6xx7"
}, {
"type" : "WEB",
"url" : "https://github.com/FlowiseAI/Flowise/pull/6650"
}, {
"type" : "WEB",
"url" : "https://github.com/FlowiseAI/Flowise/commit/dbec8f9fd3c42faab49416fe81ff1774a5344cba"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/FlowiseAI/Flowise"
}, {
"type" : "WEB",
"url" : "https://github.com/FlowiseAI/Flowise/releases/tag/flowise@3.1.4"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-862" ],
"severity" : "MODERATE",
"github_reviewed" : true,
"github_reviewed_at" : "2026-08-04T19:19:44Z",
"nvd_published_at" : null
}
}