Flowise Pre-auth Arbitrary File Upload
CriticalCVE-2025-71333 · Published Mar 13, 2025 · updated Jul 8, 2026
## Summary An unauthorized attacker can leverage the whitelisted route `/api/v1/attachments` to upload arbitrary files when the `storageType` is set to **local** (default). ## Details When a new request arrives, the system first checks if the URL starts with `/api/v1/`. If it does, the system then verifies whether the URL is included in the whitelist (*whitelistURLs*). If the URL is whitelisted, the request proceeds; otherwise, the system enforces authentication. @ */packages/server/src/index.ts* ```typescript this.app.use(async (req, res, next) => { // Step 1: Check if the req path contains /api/v1 regardless of case if (URL_CASE_INSENSITIVE_REGEX.test(req.path)) { // Step 2: Check if the req path is case sensitive if (URL_CASE_SENSITIVE_REGEX.test(req.path)) { // Step 3: Check if the req path is in the whitelist const isWhitelisted = whitelistURLs.some((url) => req.path.startsWith(url)) if (isWhitelisted) { next() } else if (req.headers['x-request-from'] === 'internal') { ...
Affected versions
| Package | Affected | Fixed in |
|---|---|---|
| flowise npm | <= 2.2.7 | No fix yet |
Details and references
## Summary An unauthorized attacker can leverage the whitelisted route `/api/v1/attachments` to upload arbitrary files when the `storageType` is set to **local** (default). ## Details When a new request arrives, the system first checks if the URL starts with `/api/v1/`. If it does, the system then verifies whether the URL is included in the whitelist (*whitelistURLs*). If the URL is whitelisted, the request proceeds; otherwise, the system enforces authentication. @ */packages/server/src/index.ts* ```typescript this.app.use(async (req, res, next) => { // Step 1: Check if the req path contains /api/v1 regardless of case if (URL_CASE_INSENSITIVE_REGEX.test(req.path)) { // Step 2: Check if the req path is case sensitive if (URL_CASE_SENSITIVE_REGEX.test(req.path)) { // Step 3: Check if the req path is in the whitelist const isWhitelisted = whitelistURLs.some((url) => req.path.startsWith(url)) if (isWhitelisted) { next() } else if (req.headers['x-request-from'] === 'internal') { basicAuthMiddleware(req, res, next) } else { const isKeyValidated = await validateAPIKey(req) if (!isKeyValidated) { return res.status(401).json({ error: 'Unauthorized Access' }) } next() } } else { return res.status(401).json({ error: 'Unauthorized Access' }) } } else { // If the req path does not contain /api/v1, then allow the request to pass through, example: /assets, /canvas next() } } ``` **The whitelist is defined as follows** ```typescript export const WHITELIST_URLS = [ '/api/v1/verify/apikey/', '/api/v1/chatflows/apikey/', '/api/v1/public-chatflows', '/api/v1/public-chatbotConfig', '/api/v1/prediction/', '/api/v1/vector/upsert/', '/api/v1/node-icon/', '/api/v1/components-credentials-icon/', '/api/v1/chatflows-streaming', '/api/v1/chatflows-uploads', '/api/v1/openai-assistants-file/download', '/api/v1/feedback', '/api/v1/leads', '/api/v1/get-upload-file', '/api/v1/ip', '/api/v1/ping', '/api/v1/version', '/api/v1/attachments', '/api/v1/metrics' ] ``` This means that every route in the whitelist does not require authentication. Now, let's examine the `/api/v1/attachments` route. @ */packages/server/src/routes/attachments/index.ts* ```typescript const router = express.Router() // CREATE router.post('/:chatflowId/:chatId', getMulterStorage().array('files'), attachmentsController.createAttachment) export default router ``` After several calls, the request reaches the `createFileAttachment` function @ (*packages/server/src/utils/createAttachment.ts*) Initially, the function retrieves *chatflowid* and *chatId* from the request without any additional validation. The only check performed is whether these parameters exist in the request. ```typescript const chatflowid = req.params.chatflowId if (!chatflowid) { throw new Error( 'Params chatflowId is required! Please provide chatflowId and chatId in the URL: /api/v1/attachments/:chatflowId/:chatId' ) } const chatId = req.params.chatId if (!chatId) { throw new Error( 'Params chatId is required! Please provide chatflowId and chatId in the URL: /api/v1/attachments/:chatflowId/:chatId' ) } ``` Next, the function retrieves the uploaded files and attempts to add them to the storage by calling the `addArrayFilesToStorage` function. ```typescript const files = (req.files as Express.Multer.Fil
- CVSS 4.0
- CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
- Severity from
- GitHub (reviewed advisory)
- Weakness
- CWE-434
- Also known as
- CVE-2025-71333
More Flowise advisories
All Flowise| Date | Advisory | Severity | Fixed in |
|---|---|---|---|
| Aug 142025 | Flowise OS command remote code execution | Critical9.8 | No fix yet |
| Apr 72025 | FlowiseDB vulnerable to SQL Injection by authenticated users | Medium5.9 | No fix yet |
| Mar 142025 | Flowise allows arbitrary file write to RCE | Critical10.0 | No fix yet |
| Mar 52025 | FlowiseAI Flowise arbitrary file upload vulnerability | High | No fix yet |
| Nov 212024 | Flowise OverrideConfig security vulnerability | High | 2.1.4 |
| Sep 252024 | Flowise and Flowise Chat Embed vulnerable to Stored Cross-site Scripting | Medium9.6 | 2.1.1 |