GHSA-8gj2-2cvc-6xx7: Flowise: missing auth on TTS drains owner's API budget
GHSA-8gj2-2cvc-6xx7MEDIUMFlowise's text-to-speech generation endpoint is intentionally left unauthenticated, but it fails to verify that the referenced chatflow is actually public, so anyone who knows a chatflow's UUID can ride on that chatflow owner's OpenAI or ElevenLabs credentials to generate unlimited speech audio — including for chatflows explicitly marked private. There's no CVSS score or EPSS data published and it isn't in CISA KEV, but exploitation requires nothing more than a UUID and a single curl request, which puts attacker effort at the low end even without a public exploit or scanner template in the wild. The blast radius is every self-hosted Flowise deployment through version 3.1.3 with TTS configured, and because this is an AI-agent platform that wires API keys directly into chatflows, the practical outcome is a straight line from a leaked or guessed link to a real invoice — OpenAI TTS runs about $15 per million characters and there's no built-in rate limit to cap the damage. Patch to Flowise 3.1.4 immediately, and audit OpenAI/ElevenLabs billing for any TTS-enabled chatflow that may have been reachable before patching.
What is the risk?
Rated medium severity by the vendor, but exploitability is effectively trivial: no authentication, no special privileges, and no AI/ML domain knowledge required — just an unauthenticated HTTP POST with a known or guessed chatflow UUID. Impact is financial (credential/quota abuse) and availability (denial of service via budget exhaustion) rather than data exposure, since the underlying API key is never returned to the attacker. No public PoC repo, Nuclei template, or KEV listing exists yet, but the low bar to exploit and the presence of a public GitHub Advisory with full technical detail and a working curl PoC mean opportunistic scanning is plausible in the near term. Exposure is limited to self-hosted/on-prem Flowise instances with TTS nodes configured — SaaS-hosted Flowise Cloud users are not necessarily affected the same way, but self-hosted deployments (the common enterprise pattern) are.
How does the attack unfold?
What systems are affected?
| Package | Ecosystem | Vulnerable Range | Patched |
|---|---|---|---|
| Flowise | npm | <= 3.1.3 | 3.1.4 |
Do you use Flowise? You're affected.
How severe is it?
What should I do?
1 stepUpgrade to Flowise 3.1.4 or later immediately — this is the vendor-shipped fix that adds the missing
isPubliccheck before using a chatflow's TTS credential unauthenticated. If immediate upgrade isn't possible, remove/api/v1/text-to-speech/generatefrom the auth whitelist inconstants.tsor block it at a reverse proxy/WAF pending patch. Post-patch, add rate limiting on the TTS endpoint (per the advisory's own recommendation) since even public chatflows remain abusable for cost harvesting, and check OpenAI/ElevenLabs billing dashboards for anomalous character volume or spend spikes as a detection signal. Treat chatflow UUIDs as sensitive — avoid embedding them in public docs, screenshots, or marketing links — and rotate TTS-linked credentials for any chatflow that was internet-reachable before patching.
How is it classified?
Which compliance frameworks are affected?
This CVE is relevant to:
Frequently Asked Questions
What is GHSA-8gj2-2cvc-6xx7?
Flowise's text-to-speech generation endpoint is intentionally left unauthenticated, but it fails to verify that the referenced chatflow is actually public, so anyone who knows a chatflow's UUID can ride on that chatflow owner's OpenAI or ElevenLabs credentials to generate unlimited speech audio — including for chatflows explicitly marked private. There's no CVSS score or EPSS data published and it isn't in CISA KEV, but exploitation requires nothing more than a UUID and a single curl request, which puts attacker effort at the low end even without a public exploit or scanner template in the wild. The blast radius is every self-hosted Flowise deployment through version 3.1.3 with TTS configured, and because this is an AI-agent platform that wires API keys directly into chatflows, the practical outcome is a straight line from a leaked or guessed link to a real invoice — OpenAI TTS runs about $15 per million characters and there's no built-in rate limit to cap the damage. Patch to Flowise 3.1.4 immediately, and audit OpenAI/ElevenLabs billing for any TTS-enabled chatflow that may have been reachable before patching.
Is GHSA-8gj2-2cvc-6xx7 actively exploited?
No confirmed active exploitation of GHSA-8gj2-2cvc-6xx7 has been reported, but organizations should still patch proactively.
How to fix GHSA-8gj2-2cvc-6xx7?
Upgrade to Flowise 3.1.4 or later immediately — this is the vendor-shipped fix that adds the missing `isPublic` check before using a chatflow's TTS credential unauthenticated. If immediate upgrade isn't possible, remove `/api/v1/text-to-speech/generate` from the auth whitelist in `constants.ts` or block it at a reverse proxy/WAF pending patch. Post-patch, add rate limiting on the TTS endpoint (per the advisory's own recommendation) since even public chatflows remain abusable for cost harvesting, and check OpenAI/ElevenLabs billing dashboards for anomalous character volume or spend spikes as a detection signal. Treat chatflow UUIDs as sensitive — avoid embedding them in public docs, screenshots, or marketing links — and rotate TTS-linked credentials for any chatflow that was internet-reachable before patching.
What systems are affected by GHSA-8gj2-2cvc-6xx7?
This vulnerability affects the following AI/ML architecture patterns: agent frameworks, conversational/voice AI interfaces.
What is the CVSS score for GHSA-8gj2-2cvc-6xx7?
No CVSS score has been assigned yet.
What is the AI security impact?
Affected AI Architectures
MITRE ATLAS Techniques
AML.T0029Denial of AI ServiceAML.T0034Cost HarvestingAML.T0049Exploit Public-Facing ApplicationCompliance Controls Affected
What are the technical details?
Original Advisory
## Summary The `/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. ## Details The 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`: ```typescript '/api/v1/text-to-speech/generate', ``` When a `chatflowId` is provided and the user is not authenticated (no `req.user`), the controller falls back to fetching the chatflow without workspace scoping: ```typescript // packages/server/src/controllers/text-to-speech/index.ts:36-42 if (workspaceId) { chatflow = await chatflowsService.getChatflowById(chatflowId, workspaceId) } else { // Fallback: get workspaceId from chatflow when req.user.activeWorkspaceId is not set chatflow = await chatflowsService.getChatflowById(chatflowId) // NO isPublic check workspaceId = chatflow.workspaceId } ``` The `getChatflowById` function at `packages/server/src/services/chatflows/index.ts:247-272` fetches any chatflow by ID when `workspaceId` is not provided: ```typescript const dbResponse = await appServer.AppDataSource.getRepository(ChatFlow).findOne({ where: { id: chatflowId, ...(workspaceId ? { workspaceId } : {}) // No workspace filter when workspaceId is undefined } }) ``` The controller then extracts the TTS provider configuration from the chatflow: ```typescript // packages/server/src/controllers/text-to-speech/index.ts:51-66 const ttsConfig = JSON.parse(chatflow.textToSpeech) const activeProviderKey = Object.keys(ttsConfig).find(key => ttsConfig[key].status === true) const providerConfig = ttsConfig[activeProviderKey] provider = activeProviderKey credentialId = providerConfig.credentialId // Extracted from private chatflow ``` This `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`: ```typescript const credentialId = textToSpeechConfig.credentialId as string const credentialData = await getCredentialData(credentialId ?? '', options) ``` ## PoC ```bash # Step 1: Know a chatflow UUID that has TTS enabled (any chatflow, public or private) CHATFLOW_ID="<any-chatflow-uuid-with-tts-enabled>" # Step 2: Abuse the TTS credential to generate audio without authentication curl -X POST "http://localhost:3000/api/v1/text-to-speech/generate" \ -H "Content-Type: application/json" \ -d '{ "chatflowId": "'${CHATFLOW_ID}'", "chatId": "attacker-chat-1", "chatMessageId": "msg-1", "text": "This is a test of unauthorized TTS generation using someone elses API key" }' # Expected: Returns SSE stream with TTS audio data using the chatflow owner's OpenAI/ElevenLabs credentials # event: tts_start # data: {"event":"tts_start","data":{"chatMessageId":"msg-1","format":"mp3"}} # event: tts_data # data: {"event":"tts_data","data":{"chatMessageId":"msg-1","audioChunk":"<base64-audio>"}} # Step 3: Repeat with large text to incur costs curl -X POST "http://localhost:3000/api/v1/text-to-speech/generate" \ -H "Content-Type: application/json" \ -d '{ "chatflowId": "'${CHATFLOW_ID}'", "chatId": "attacker-chat-2", "chatMessageId": "msg-2", "text": "'$(python3 -c "print('A' * 4096)")'" }' ``` ## Impact - **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. - **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. - **Denial of Service**: By exhausting the API quota/budget of the credential, the attacker can deny service to legitimate users of the chatflow. - **Affects Private Chatflows**: This vulnerability affects all chatflows with TTS configured, including those explicitly marked as private (`isPublic: false`). ## Recommended Fix 1. Check `isPublic` before allowing unauthenticated TTS generation: ```typescript // packages/server/src/controllers/text-to-speech/index.ts if (chatflowId) { let chatflow; let workspaceId = req.user?.activeWorkspaceId; if (workspaceId) { chatflow = await chatflowsService.getChatflowById(chatflowId, workspaceId) } else { chatflow = await chatflowsService.getChatflowById(chatflowId) // Verify the chatflow is public before using its credentials if (!chatflow.isPublic) { throw new InternalFlowiseError( StatusCodes.UNAUTHORIZED, 'TTS generation requires authentication for non-public chatflows' ) } workspaceId = chatflow.workspaceId } // ... rest of the function } ``` 2. Consider applying rate limiting to the TTS endpoint to prevent abuse even for public chatflows.
Exploitation Scenario
An attacker obtains a Flowise chatflow UUID — via a leaked support link, a screenshot in documentation, exposed client-side code, or brute-force enumeration — and confirms it has TTS enabled. Without authenticating or holding any permission, they POST to `/api/v1/text-to-speech/generate` with that `chatflowId` and a large text payload; Flowise server-side decrypts and uses the chatflow owner's stored OpenAI or ElevenLabs API key to synthesize the audio and stream it back over SSE. The attacker scripts repeated large-text requests to run up the owner's API bill or exhaust their provider quota, causing direct financial loss and denying TTS service to the chatflow's legitimate users — and because the actual API key never appears in attacker-visible traffic, the abuse is hard to attribute without cross-checking provider billing logs against Flowise access logs.
Weaknesses (CWE)
CWE-862 — Missing Authorization: The product does not perform an authorization check when an actor attempts to access a resource or perform an action.
- [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-7133810.0Flowise: unauthenticated file write enables RCE
Same package: flowiseCVE-2025-5952810.0Flowise: Unauthenticated RCE via MCP config injection
Same package: flowiseCVE-2026-464429.9Flowise: sandbox escape enables authenticated RCE
Same package: flowiseCVE-2025-619139.9Flowise: path traversal in file tools leads to RCE
Same package: flowiseCVE-2026-409339.9Flowise: RCE via MCP stdio command injection
Same package: flowise