GHSA-8gj2-2cvc-6xx7: Flowise: missing auth on TTS drains owner's API budget

GHSA-8gj2-2cvc-6xx7MEDIUM
Published August 4, 2026
CISO Take

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.

Sources:GitHub AdvisoryATLAS

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?

Reconnaissance
Attacker obtains a Flowise chatflow UUID with TTS enabled via a leaked link, exposed screenshot, or enumeration.
AML.T0006
Unauthenticated exploitation
Attacker sends an unauthenticated POST to the whitelisted TTS endpoint with the chatflowId, bypassing the missing isPublic ownership check.
AML.T0049
Credential abuse
Flowise server-side decrypts and uses the chatflow owner's OpenAI/ElevenLabs credential to generate TTS audio on the attacker's behalf.
AML.T0034
Impact
Repeated abuse runs up the owner's API bill and/or exhausts their provider quota, causing financial loss and denial of service to legitimate users.
AML.T0029

What systems are affected?

PackageEcosystemVulnerable RangePatched
Flowisenpm<= 3.1.33.1.4

Do you use Flowise? You're affected.

How severe is it?

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

What should I do?

1 step
  1. 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.

How is it classified?

Which compliance frameworks are affected?

This CVE is relevant to:

EU AI Act
Article 15-Accuracy, robustness and cybersecurity
ISO 42001
A.6.2.4-AI system access controls
NIST AI RMF
MEASURE 2.7-AI system security and resilience are evaluated and documented
OWASP LLM Top 10
LLM10:2025-Unbounded Consumption

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

agent frameworksconversational/voice AI interfaces

MITRE ATLAS Techniques

AML.T0029Denial of AI Service
AML.T0034Cost Harvesting
AML.T0049Exploit Public-Facing Application

Compliance Controls Affected

EU AI Act: Article 15
ISO 42001: A.6.2.4
NIST AI RMF: MEASURE 2.7
OWASP LLM Top 10: LLM10:2025

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.

Timeline

Published
August 4, 2026
Last Modified
August 4, 2026
First Seen
August 4, 2026

Related Vulnerabilities