The text-to-speech generation endpoint (POST /api/v1/text-to-speech/generate) is whitelisted (no auth) and accepts a credentialId directly in the request body. When called without a chatflowId, the endpoint uses the provided credentialId to decrypt the stored credential (e.g., OpenAI or ElevenLabs API key) and generate speech.
// packages/server/src/controllers/text-to-speech/index.ts:58-64
} else {
// Use TTS config from request body
provider = bodyProvider
credentialId = bodyCredentialId // ← attacker-controlled credential ID
voice = bodyVoice
model = bodyModel
}
POST /api/v1/text-to-speech/generate with arbitrary credentialId in body: endpoint processes request, sends SSE tts_start event, only fails when credential doesn't exist — proves code path runs without authentication.
Remove the TTS endpoint from WHITELIST_URLS or validate that the credential belongs to the chatflow being used:
// Only allow credentialId when it matches the chatflow's TTS configuration
if (!chatflowId) {
return res.status(401).json({ message: 'Authentication required' })
}
packages/server/src/controllers/text-to-speech/index.ts lines 10-162packages/server/src/utils/constants.ts line 41 (whitelist entry){
"github_reviewed": true,
"github_reviewed_at": "2026-04-17T21:35:14Z",
"cwe_ids": [
"CWE-639"
],
"severity": "HIGH",
"nvd_published_at": "2026-04-23T20:16:16Z"
}