{"vulnerability": "CVE-2026-6925", "sightings": [{"uuid": "f3838382-906c-4c5e-9f72-658c091abddd", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-69252", "type": "seen", "source": "https://gist.github.com/alon710/2dd72db9fde8130e6ba6e6299e77ffd0", "content": "# CVE-2026-69252: CVE-2026-69252: Broken Workspace Isolation and Missing Authorization in Flowise File Management API\n\n&gt; **CVSS Score:** 7.2\n&gt; **Published:** 2026-08-04\n&gt; **Full Report:** https://cvereports.com/reports/CVE-2026-69252\n\n## Summary\nCVE-2026-69252 represents a missing authorization check (CWE-862) in the files API route (`/api/v1/files`) of Flowise, a drag-and-drop user interface for building LLM flows. Prior to version 3.1.3, an authenticated API key or user could list, access, and delete files across arbitrary workspaces inside an organization, completely bypassing workspace logical boundaries.\n\n## TL;DR\nFlowise prior to 3.1.3 allows authenticated users with low-privilege API keys to read and delete files across different workspaces due to missing authorization checks on the `/api/v1/files` endpoint.\n\n## Exploit Status: POC\n\n## Technical Details\n\n- **CWE ID**: CWE-862\n- **Attack Vector**: Network (AV:N)\n- **CVSS v4.0 Score**: 7.2 (High)\n- **Exploit Status**: PoC (Proof-of-Concept)\n- **Impact**: Confidentiality (High), Availability (High)\n- **KEV Status**: Not Listed\n\n## Affected Systems\n\n- Flowise LLM Orchestration Platform\n- **Flowise**: &lt; 3.1.3 (Fixed in: `3.1.3`)\n\n## Mitigation\n\n- Upgrade Flowise to version 3.1.3 or higher\n- Manually disable the vulnerable `/files` routes in source files if upgrading is delayed\n- Implement WAF rules to block GET and DELETE requests to `/api/v1/files`\n\n**Remediation Steps:**\n1. Verify current Flowise version by running `npm list -g flowise`\n2. Upgrade the package globally using `npm install -g flowise@3.1.3`\n3. Restart the Flowise service to apply changes\n4. Validate that requests to `/api/v1/files` return an HTTP 404 response\n\n## References\n\n- [GitHub Security Advisory: Missing Authorization on /api/v1/files](https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-wp74-f5hh-5f3r)\n- [Flowise Pull Request #6435](https://github.com/FlowiseAI/Flowise/pull/6435)\n- [Flowise Patch Commit bc22bf8baec95b6a3d6e1b3563b4f03491cd6fbb](https://github.com/FlowiseAI/Flowise/commit/bc22bf8baec95b6a3d6e1b3563b4f03491cd6fbb)\n- [Flowise v3.1.3 Release Tag](https://github.com/FlowiseAI/Flowise/releases/tag/flowise@3.1.3)\n\n\n---\n*Generated by [CVEReports](https://cvereports.com/reports/CVE-2026-69252) - Automated Vulnerability Intelligence*", "creation_timestamp": "2026-08-04T15:32:39.452795Z"}, {"uuid": "d7d739f7-ba1b-4fcd-b8e3-c275fd1b12f4", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-69250", "type": "seen", "source": "https://bsky.app/profile/cve.skyfleet.blue/post/6thxbosiashei", "content": "CVE-2026-69250 - Flowise: Unauthenticated OAuth2 Refresh Enables Non-Blind SSRF and Secret Exfiltration\nCVE ID : CVE-2026-69250\n \n Published : Aug. 4, 2026, 3:16 p.m. | 59\u00a0minutes ago\n \n Description : Flowise is a drag &amp; drop user interface to build a customized large lang...", "creation_timestamp": "2026-08-04T16:29:36.726827Z"}, {"uuid": "073fc14e-da75-43c8-90eb-0debcf4fd1d6", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-69258", "type": "seen", "source": "https://gist.github.com/alon710/6149a4f7f7f2ae19b65c163d6f6db13a", "content": "# CVE-2026-69258: CVE-2026-69258: Unauthenticated Property Injection and Authorization Bypass in Flowise\n\n&gt; **CVSS Score:** 8.8\n&gt; **Published:** 2026-08-04\n&gt; **Full Report:** https://cvereports.com/reports/CVE-2026-69258\n\n## Summary\nCVE-2026-69258 is a high-severity property injection and unauthenticated authorization bypass vulnerability in Flowise, a drag-and-drop orchestration interface for building customized LLM workflows. In affected versions prior to 3.1.3, the unauthenticated prediction API endpoint (`POST /api/v1/prediction/:id`) processed client-controlled parameters inside an `overrideConfig` payload without authorization checks. The backend unconditionally spread this object into internal context structures, enabling unauthenticated remote attackers to overwrite critical session values, pollute execution contexts, and bypass flow restrictions.\n\n## TL;DR\nAn unauthenticated property injection vulnerability in Flowise (&lt; 3.1.3) allows remote attackers to overwrite critical workflow parameters, facilitating session hijacking and prompt injection.\n\n## Exploit Status: POC\n\n## Technical Details\n\n- **CWE ID**: CWE-915 / CWE-639\n- **Attack Vector**: Network\n- **CVSS v4.0 Score**: 8.8\n- **Vulnerability Class**: Property Injection / Authorization Bypass\n- **Exploit Status**: Proof-of-Concept Available\n- **Remediation**: Upgrade to v3.1.3 or higher\n\n## Affected Systems\n\n- Flowise deployments exposing unauthenticated prediction endpoints (&lt; 3.1.3)\n- **Flowise**: &lt; 3.1.3 (Fixed in: `3.1.3`)\n\n## Mitigation\n\n- Upgrade Flowise server instances to version 3.1.3 or higher immediately.\n- Deploy WAF rules to block JSON requests targeting prediction endpoints that contain 'overrideConfig' along with internal state keys.\n- Audit existing workflow schemas to identify and secure any reliance on user-supplied variables within administrative routing nodes.\n\n**Remediation Steps:**\n1. Determine current package version using 'npm list -g flowise' or checking the container version.\n2. Run 'npm install -g flowise@latest' or update the docker-compose image to 'flowiseai/flowise:3.1.3'.\n3. Restart the Flowise service to apply configuration changes.\n4. Verify that the prediction API endpoint now safely ignores unauthenticated parameters inside the overrideConfig parameter block.\n\n## References\n\n- [GitHub Security Advisory GHSA-6vh2-wg4h-4vwj](https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-6vh2-wg4h-4vwj)\n- [Flowise Pull Request #6279](https://github.com/FlowiseAI/Flowise/pull/6279)\n- [Flowise Security Fix Commit](https://github.com/FlowiseAI/Flowise/commit/23b997ee5ef9e269b628bad0f56f1ecb86bd2fca)\n- [Flowise v3.1.3 Release Notes](https://github.com/FlowiseAI/Flowise/releases/tag/flowise@3.1.3)\n- [CVE Official Entry](https://www.cve.org/CVERecord?id=CVE-2026-69258)\n\n\n---\n*Generated by [CVEReports](https://cvereports.com/reports/CVE-2026-69258) - Automated Vulnerability Intelligence*", "creation_timestamp": "2026-08-04T16:31:33.352278Z"}, {"uuid": "e615d362-62fe-44d2-a929-35bba8f16d19", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "86ecb4e1-bb32-44d5-9f39-8a4673af8385", "vulnerability": "CVE-2026-69258", "type": "published-proof-of-concept", "source": "https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-6vh2-wg4h-4vwj", "content": "", "creation_timestamp": "2026-08-04T16:35:03.636398Z"}, {"uuid": "449e5edc-e0b4-4be9-b8c2-2f663e2e7f5f", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "86ecb4e1-bb32-44d5-9f39-8a4673af8385", "vulnerability": "CVE-2026-69257", "type": "published-proof-of-concept", "source": "https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-c6xh-wv4j-ppv5", "content": "", "creation_timestamp": "2026-08-04T16:35:15.139686Z"}, {"uuid": "9b67fbd2-2ff3-473b-bc44-b724145e569e", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "86ecb4e1-bb32-44d5-9f39-8a4673af8385", "vulnerability": "CVE-2026-69254", "type": "published-proof-of-concept", "source": "https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-3769-jgqc-cxm7", "content": "", "creation_timestamp": "2026-08-04T16:35:19.742909Z"}, {"uuid": "0e48dd97-82a8-4f64-82db-e4536bd410d0", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "86ecb4e1-bb32-44d5-9f39-8a4673af8385", "vulnerability": "CVE-2026-69256", "type": "published-proof-of-concept", "source": "https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-x6vm-w76m-8j7g", "content": "", "creation_timestamp": "2026-08-04T16:35:17.336269Z"}, {"uuid": "4980b26c-f27f-4be9-a3f7-f51a6ba2c857", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "86ecb4e1-bb32-44d5-9f39-8a4673af8385", "vulnerability": "CVE-2026-69253", "type": "published-proof-of-concept", "source": "https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-wg86-r78f-74mp", "content": "", "creation_timestamp": "2026-08-04T16:35:21.879899Z"}, {"uuid": "7814d80b-187b-43d6-a850-2e4cb1f3a553", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "86ecb4e1-bb32-44d5-9f39-8a4673af8385", "vulnerability": "CVE-2026-69252", "type": "published-proof-of-concept", "source": "https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-wp74-f5hh-5f3r", "content": "", "creation_timestamp": "2026-08-04T16:35:24.715168Z"}, {"uuid": "aa5aac7c-26ec-4cef-9428-bc68b4b375e8", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "86ecb4e1-bb32-44d5-9f39-8a4673af8385", "vulnerability": "CVE-2026-69251", "type": "published-proof-of-concept", "source": "https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-g32j-mmxr-gfq5", "content": "", "creation_timestamp": "2026-08-04T16:35:26.915937Z"}, {"uuid": "110f6c04-6fca-454d-8147-0dac553e5d94", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "86ecb4e1-bb32-44d5-9f39-8a4673af8385", "vulnerability": "CVE-2026-69250", "type": "published-proof-of-concept", "source": "https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-r745-8hwv-h473", "content": "", "creation_timestamp": "2026-08-04T16:35:29.704754Z"}, {"uuid": "c4f2d478-dc3f-4bac-845f-44384d6832c9", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-69254", "type": "seen", "source": "https://bsky.app/profile/cve.skyfleet.blue/post/iid3bk3zrlm5m", "content": "CVE-2026-69254 - Flowise: RCE via NodeVM Sandbox Escape in executeJavaScriptCode() nodeVMOptions Override\nCVE ID : CVE-2026-69254\n \n Published : Aug. 4, 2026, 3:28 p.m. | 47\u00a0minutes ago\n \n Description : Flowise is a drag &amp; drop user interface to build a customized large la...", "creation_timestamp": "2026-08-04T16:41:33.819509Z"}, {"uuid": "645c14e4-2261-4ec3-958d-be1ea5dffe0b", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-69258", "type": "seen", "source": "https://bsky.app/profile/cve.skyfleet.blue/post/dc4vgbfsfr6zf", "content": "CVE-2026-69258 - Flowise: Unauthenticated Property Injection into Flow Execution Context via Ungated `overrideConfig` Spread in Prediction API\nCVE ID : CVE-2026-69258\n \n Published : Aug. 4, 2026, 5:17 p.m. | 29\u00a0minutes ago\n \n Description : Flowise is a drag &amp; drop user int...", "creation_timestamp": "2026-08-04T17:54:36.042410Z"}, {"uuid": "9927a0ec-9ae1-4fa6-b8cb-4ceeae57afa3", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-69253", "type": "seen", "source": "https://bsky.app/profile/stackflag.bsky.social/post/3msbm6og5rg23", "content": "CVE-2026-69253 - flowise\nFlowise AI, a low-code platform for building AI applications, has a security issue that could allow an attacker to execute malicious code on your system. This is a concern for anyone\u2026\n\nToo many irrelevant or confusing CVEs? Use stackflag.com\n\n#flowise #npm #CVE #infosec", "creation_timestamp": "2026-08-04T18:08:05.271264Z"}, {"uuid": "98fc8746-a7a1-4626-83f9-44532562f703", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-69254", "type": "seen", "source": "https://bsky.app/profile/stackflag.bsky.social/post/3msbmcbbk4j2a", "content": "CVE-2026-69254 - flowise\nA vulnerability in Flowise allows authenticated users to execute arbitrary system commands as root on the server. This can happen when a user registers a new route. To fix this, update\u2026\n\nToo many irrelevant or confusing CVEs? Use stackflag.com\n\n#flowise #npm #CVE #infosec", "creation_timestamp": "2026-08-04T18:10:05.696226Z"}, {"uuid": "992f3d3a-9310-46d7-b8e0-ede65a8dbb79", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-69256", "type": "seen", "source": "https://bsky.app/profile/stackflag.bsky.social/post/3msbmjevv4u2f", "content": "CVE-2026-69256 - flowise\nA vulnerability in the CSVAgent allows users to inject malicious code, which can be executed on the system. This can happen if a user provides specially crafted CSV data that\u2026\n\nToo many irrelevant or confusing CVEs? Use stackflag.com\n\n#flowise #flowiseai #npm #CVE #infosec", "creation_timestamp": "2026-08-04T18:14:04.673342Z"}, {"uuid": "36d6dfa9-a582-4bc0-9981-f68ad1400972", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-69255", "type": "seen", "source": "https://bsky.app/profile/stackflag.bsky.social/post/3msbmftr7f42o", "content": "CVE-2026-69255 - flowise\nA security issue in Flowise 3.1.2 allows attackers to execute arbitrary commands as the root user. This can happen when a malicious user uploads a specially crafted CSV file.\u2026\n\nToo many irrelevant or confusing CVEs? Use stackflag.com\n\n#flowise #flowiseai #npm #CVE #infosec", "creation_timestamp": "2026-08-04T18:12:06.032729Z"}, {"uuid": "2d484c55-28cd-4699-9e80-4185852ae4ca", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-69259", "type": "seen", "source": "https://bsky.app/profile/stackflag.bsky.social/post/3msbmjgbfph2b", "content": "CVE-2026-69259 - flowise\nFlowiseAI 3.1.2 has a security weakness that could let an attacker access a local database without permission. This could happen if an attacker can manipulate the database\u2026\n\nToo many irrelevant or confusing CVEs? Use stackflag.com\n\n#flowise #flowiseai #npm #CVE #infosec", "creation_timestamp": "2026-08-04T18:14:05.844617Z"}, {"uuid": "6ab66bc1-230a-43d6-9fa5-d02f108ccdd6", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "86ecb4e1-bb32-44d5-9f39-8a4673af8385", "vulnerability": "CVE-2026-69259", "type": "published-proof-of-concept", "source": "https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-x3hf-7cj6-3r4m", "content": "", "creation_timestamp": "2026-08-04T18:35:12.755061Z"}, {"uuid": "9dab9bf1-8d95-42fa-8295-b0d093923f74", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-69258", "type": "seen", "source": "https://bsky.app/profile/hackernoon.com/post/3mucmwuo5za2t", "content": "CVE-2026-69258: two ungated spread operators let an unauthenticated caller write into the flow execution context of any public Flowise chatflow. #flowisevulnerability", "creation_timestamp": "2026-08-30T14:44:40.519555Z"}, {"uuid": "8873af65-2720-465b-8462-179c8746c994", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-69258", "type": "seen", "source": "https://gist.github.com/haidang-infosec/402db84bee7aca2f57bb109b31574649", "content": "# CVE-2026-71962: Unauthenticated Cross-Tenant File Disclosure in Flowise via `openai-assistants-file/download`\n\n**CVE ID:** CVE-2026-71962\n**CNA:** VulnCheck\n**Author:** Mai Hai Dang (haidang.infosec@gmail.com)\n**Report date:** 2026-08-09\n**Product:** Flowise ([FlowiseAI/Flowise](https://github.com/FlowiseAI/Flowise), npm package `flowise`)\n**Affected component:** `packages/server` \u2014 REST API\n**Vulnerability class:** Missing Authorization / Insecure Direct Object Reference (IDOR)\n**CWE:** CWE-862 (Missing Authorization) \u2014 primary; CWE-639 (Authorization Bypass Through User-Controlled Key) \u2014 secondary\n**CVSS 3.1:** `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N` \u2014 **7.5 (High)**\n**CVSS 4.0:** `CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N` \u2014 **8.7 (High)**\n\n---\n\n## 1. Summary\n\nThe Flowise REST API endpoint `POST /api/v1/openai-assistants-file/download` is served without any authentication check \u2014 it is listed in the server's global `WHITELIST_URLS`, which bypasses both session-cookie and API-key authentication for any request whose path matches it. The handler behind this endpoint (`getFileFromAssistant`) resolves and streams a file from the server's file storage (local disk or S3, depending on deployment) using three client-supplied identifiers \u2014 `chatflowId`, `chatId`, `fileName` \u2014 without ever verifying that the target chatflow is public (`isPublic: true`) or that the requester belongs to the workspace that owns it.\n\nAn unauthenticated requester who knows a valid `chatflowId`/`chatId`/`fileName` tuple can retrieve the corresponding stored file without any authentication or workspace-membership check. This was directly reproduced against a private chatflow (Section 4). Cross-workspace/cross-organization impact is not separately runtime-tested with two tenants, but follows directly from the handler's data flow: `getFileFromAssistant` resolves the owning workspace and organization from the *supplied* `chatflowId` alone (Section 3.3) and never evaluates the requester's identity, so the same zero-authentication request works identically regardless of which workspace or organization the target chatflow belongs to.\n\nThis is a distinct defect from the previously disclosed and patched path-traversal vulnerabilities affecting the same endpoint (GHSA-99pg-hqvx-r4gf, GHSA-q67q-549q-p849); those were fixed by adding strict path-traversal validation to `chatflowId`/`chatId`/`fileName`, which is confirmed present and effective in the version tested. The defect reported here is a pure authorization gap: the request never leaves the *intended* storage path, it simply is never checked for ownership.\n\n## 2. Affected Versions\n\n| Scope | Status |\n|---|---|\n| npm `flowise` `3.1.4` (latest published release, git tag `flowise@3.1.4` = commit `a65f81bb`, 2026-07-29) | Confirmed by runtime reproduction (Section 4) |\n| Current public GitHub `main` branch HEAD | Confirmed by source inspection (code path unchanged relative to `3.1.4`) |\n| npm `flowise` `2.2.4` \u2013 `3.1.3` | Presumed affected, based on `git log`/`git blame` showing the vulnerable code has been present, unmodified, since `2.2.4`; not individually runtime-tested per version |\n\nThe PoC in this report was reproduced by checking out the official release tag directly (`git checkout flowise@3.1.4`), removing any ambiguity about whether the finding applies to unreleased code.\n\n**Version history (established via `git log`/`git blame` against the public repository):**\n- The `WHITELIST_URLS` entry for this exact path was introduced in commit `8d266052` (\"Feature/update upsert API\"), dated 2025-01-09, first shipped in release `2.2.4`. `git log -S` against the literal route string shows this is the only commit that has ever touched it \u2014 it has never been removed or narrowed.\n- The `getFileFromAssistant` handler has never, at any point in its history, contained an `isPublic`, `req.user`, or workspace-membership check (`git log -S\"isPublic\"` on the controller file returns zero matches).\n- The most recent related fix in this file, commit `0b74fc07` (\"fix: flowise-603\", 2026-08-07 \u2014 the fix for the previously reported CVE-2026-67622 credential-confused-deputy issue), added workspace scoping to three sibling handlers in the same file (`getAllOpenaiAssistants`, `getSingleOpenaiAssistant`, `uploadAssistantFiles`) but did not touch `getFileFromAssistant`.\n\n## 3. Technical Details\n\n### 3.1 Authentication bypass (whitelist)\n\n`packages/server/src/utils/constants.ts`:\n```ts\nexport const WHITELIST_URLS = [\n    ...\n    '/api/v1/openai-assistants-file/download',\n    ...\n]\n```\n\n`packages/server/src/index.ts` (global auth middleware):\n```ts\nconst isWhitelisted = whitelistURLs.some((url) =&gt; req.path.startsWith(url))\nif (isWhitelisted) {\n    next()   // skips verifyToken() (session/JWT) and validateAPIKey() entirely\n}\n```\n\n### 3.2 Route has no permission middleware\n\n`packages/server/src/routes/openai-assistants-files/index.ts` \u2014 contrast with the sibling `upload/` route on the same router, which *does* enforce RBAC:\n```ts\nrouter.post('/download/', openaiAssistantsController.getFileFromAssistant)\n\nrouter.post(\n    '/upload/',\n    checkAnyPermission('assistants:create,assistants:update'),\n    getMulterStorage().array('files'),\n    openaiAssistantsController.uploadAssistantFiles\n)\n```\n\n### 3.3 Controller performs no ownership check\n\n`packages/server/src/controllers/openai-assistants/index.ts`, `getFileFromAssistant`:\n```ts\nconst getFileFromAssistant = async (req: Request, res: Response, next: NextFunction) =&gt; {\n    const chatflowId = req.body.chatflowId as string\n    const chatId = req.body.chatId as string\n    const fileName = req.body.fileName as string\n\n    // \"This can be public API, so we can only get orgId from the chatflow\"\n    const chatflow = await appServer.AppDataSource.getRepository(ChatFlow).findOneBy({ id: chatflowId })\n    // no isPublic check\n    // no req.user / workspace check\n\n    const orgId = workspace.organizationId as string\n    res.setHeader('Content-Disposition', contentDisposition(fileName))\n    const fileStream = await streamStorageFile(chatflowId, chatId, fileName, orgId)\n    fileStream.pipe(res)\n}\n```\n\nThe comment in the source (`\"This can be public API...\"`) shows the author was aware this handler must operate without `req.user`, but never added the corresponding public/private gate.\n\n### 3.4 The codebase's own correct pattern for this exact situation\n\n`packages/server/src/controllers/chatflows/index.ts`, `getSinglePublicChatflow` \u2014 the pattern that should have been applied to `getFileFromAssistant`:\n```ts\nconst chatflow = await chatflowsService.getChatflowById(req.params.id)\nif (!chatflow) return res.status(404).json({ message: 'Chatflow not found' })\nif (chatflow.isPublic)\n    return res.status(200).json({ ...chatflow, flowData: sanitizeFlowDataForPublicEndpoint(chatflow.flowData) })\nif (!req.user) return res.status(401).json({ message: 'Unauthorized' })\nif (!workspaceIds.includes(chatflow.workspaceId))\n    return res.status(400).json({ message: 'You are not in the workspace that owns this chatflow' })\n```\nThis is the exact three-step check \u2014 (1) `chatflow.isPublic`, (2) `req.user` presence, (3) `workspaceIds.includes(chatflow.workspaceId)` \u2014 that `getFileFromAssistant` omits entirely. Its presence elsewhere in the same codebase demonstrates this is an oversight, not an intentional design decision.\n\n### 3.5 Ruled out: this is not a path-traversal bug\n\n`packages/components/src/storage/BaseStorageProvider.ts` (`sanitizeFilename`, `validatePathSecurity`) and `LocalStorageProvider.streamStorageFile` validate all three path components and reject `..`/absolute-path escape attempts before touching the filesystem. This closes off the vector exploited by the previously fixed GHSA-99pg-hqvx-r4gf / GHSA-q67q-549q-p849. The finding in this report requires no traversal \u2014 it retrieves a file from exactly the path the application itself would use, for a resource the caller has no authorization to access.\n\n### 3.6 Legitimate file-creation path (storage layout is not test-only)\n\nThe PoC in Section 4 places the victim file directly on disk as a deterministic test fixture rather than through a real chat interaction. This section establishes that the fixture's location is not artificial: it is exactly the layout Flowise's own, ordinary chat-attachment upload workflow writes to.\n\n`packages/server/src/utils/buildChatflow.ts`, in the request-handling path for chat messages that include file/image/audio uploads (`uploads`), including on public-facing chatflows with no authentication required to converse:\n```ts\nconst { totalSize } = await addSingleFileToStorage(mime, bf, filename, orgId, chatflowid, chatId)\n```\n`addSingleFileToStorage(mime, buffer, filename, orgId, chatflowid, chatId)` writes to `////` \u2014 the identical path structure `streamStorageFile` reads from in the vulnerable handler (Section 3.3):\n```\nLegitimate file creation:                     Vulnerable retrieval:\nbuildChatflow.ts (chat upload handling)       getFileFromAssistant()\n  -&gt; addSingleFileToStorage(                    -&gt; streamStorageFile(\n      mime, buffer, filename,                       chatflowId, chatId,\n      orgId, chatflowid, chatId)                     fileName, orgId)\n  -&gt; writes ///  -&gt; reads the same path\n```\nThe file in the PoC was placed directly only to create a deterministic test fixture; its path and naming layout exactly match the storage layout produced by this legitimate, unauthenticated-reachable upload workflow.\n\n### 3.7 Identifier exposure and attack prerequisites\n\nThe identifiers consumed by the vulnerable endpoint \u2014 `chatflowId`, `chatId`, `fileName` \u2014 are ordinary client-side resource locators, not authorization credentials or server-issued capability tokens:\n\n- `chatId` is generated client-side (`const [chatId, setChatId] = useState(uuidv4())`, `packages/ui/src/views/chatmessage/ChatMessage.jsx:213`) and persisted via `localStorage.setItem` (`packages/ui/src/utils/genericHelper.js:889`, `setLocalStorageChatflow`) \u2014 it is never issued or cryptographically bound to a session by the server.\n- The official frontend embeds `chatflowId`, `chatId`, and `fileName` directly, in plaintext, in file URLs it renders in the chat UI, e.g. `${baseURL}/api/v1/get-upload-file?chatflowId=${chatflowid}&amp;chatId=${chatId}&amp;fileName=${...}` (`ChatMessage.jsx:719, 1338, 1349`).\n\n`chatId` is not an authorization credential and is not cryptographically bound to the requester's identity or session. Consequently, possession of a `chatflowId`/`chatId`/`fileName` tuple must not be treated by the server as proof of authorization \u2014 yet `getFileFromAssistant` treats it as sufficient. Because these values are exposed to the browser DOM and network layer by ordinary use of the product, they may consequently appear in client-side logs, reverse-proxy or gateway logs, monitoring/APM systems, shared HTML, or diagnostic material such as exported conversations or bug reports.\n\n**What this evidence does *not* establish:** observing that identifiers for a given (e.g. public) chatflow are exposed in that chatflow's own UI does not by itself demonstrate that an attacker can obtain the tuple for an *arbitrary, unrelated private* target chatflow. This report does not claim that. The exploitation prerequisite is stated precisely as:\n\n&gt; Exploitation requires knowledge of the exact `chatflowId`/`chatId`/`fileName` tuple for the target file. This report does not rely on guessing, brute-forcing, path traversal, or bypassing UUID validation to obtain that tuple \u2014 Section 3.5 confirms no traversal path exists, and none is needed once the tuple is known. How a specific attacker obtains a specific target's tuple is scenario-dependent and outside the scope of this report; the defect is that the server performs no authorization check at all once the tuple is presented, regardless of how it was obtained.\n\n## 4. Proof of Concept\n\nReproduced end-to-end against the **official `flowise@3.1.4` release tag**, built and run via the project's own `Dockerfile` (`docker build -t flowise-local:3.1.4 .`), default configuration (local file storage, SQLite).\n\n**Scope of this PoC:** the following is directly reproduced against a single private chatflow within a single organization/workspace \u2014 a second tenant was not separately stood up. Cross-workspace/cross-organization impact is established by the handler's own logic, not by this specific run (see Section 1).\n\n### 4.1 Setup\n\n1. Created a workspace-owner account via the normal setup UI.\n2. `POST /api/v1/chatflows`, authenticated, `isPublic: false` \u2014 created the private target chatflow (`id = 3055de1b-586b-4756-9e77-da2c19b62f95`, `workspaceId = 53141120-b356-452a-b34d-28549fdbab9d`, `organizationId = b2439594-7c21-4bf7-86b6-b1d90ffd40b8`).\n3. A file was placed at the exact path the application itself uses for chat-generated/uploaded files \u2014 `////` \u2014 as a deterministic test fixture matching the legitimate upload workflow traced in Section 3.6.\n\n### 4.2 Request A \u2014 Control\n\nSent with **no** `Cookie`/`Authorization` header, targeting the equivalent metadata-read endpoint for the same resource:\n```\nGET /api/v1/chatflows/3055de1b-586b-4756-9e77-da2c19b62f95 HTTP/1.1\nHost: localhost:3000\n```\n**Response:** `HTTP/1.1 401 Unauthorized`\n```json\n{\"message\":\"Invalid or Missing token\"}\n```\nThis confirms the platform *does* enforce authentication on the equivalent, properly-guarded endpoint for the identical resource.\n\n### 4.3 Request B \u2014 Exploit\n\nSent with **no** `Cookie`/`Authorization` header at all, against the vulnerable endpoint:\n```\nPOST /api/v1/openai-assistants-file/download HTTP/1.1\nHost: localhost:3000\nContent-Type: application/json\nContent-Length: 123\n\n{\"chatflowId\":\"3055de1b-586b-4756-9e77-da2c19b62f95\",\"chatId\":\"e29b8f3a-victim-chat-01\",\"fileName\":\"secret-report.txt\"}\n```\n**Response:** `HTTP/1.1 200 OK`\n```\nContent-Disposition: attachment; filename=\"secret-report.txt\"\n\nCONFIDENTIAL - victim workspace uploaded file - should NOT be downloadable without auth\n```\n\nRequest A (targeting the exact same private resource, via the properly-guarded metadata endpoint) was correctly rejected; Request B (targeting the file-download endpoint) was not \u2014 isolating the defect to this specific handler rather than a global authentication failure.\n\n### 4.4 Additional confirmation \u2014 full unauthenticated identifier-acquisition chain\n\nIn a related finding against the same instance, the sibling whitelisted endpoint `GET /api/v1/feedback/:chatflowId` (`packages/server/src/controllers/feedback/index.ts`, `packages/server/src/utils/getChatMessageFeedback.ts`) was found to return `ChatMessageFeedback` records \u2014 including the real `chatId` for the chatflow \u2014 for **any** `chatflowId`, with the same missing-authorization pattern and no additional identifiers required:\n```\nGET /api/v1/feedback/3055de1b-586b-4756-9e77-da2c19b62f95 HTTP/1.1\nHost: localhost:3000\n```\n```json\n[{\"id\":\"...\",\"chatflowid\":\"3055de1b-...\",\"chatId\":\"e29b8f3a-victim-chat-01\",\"messageId\":\"...\",\"rating\":\"THUMBS_DOWN\",\"content\":\"...\",\"createdDate\":\"...\"}]\n```\nThe `chatId` returned by this unauthenticated request was then used, unmodified, in Request B above and successfully retrieved the file \u2014 demonstrating that an attacker starting with **only a `chatflowId`** (routinely exposed in public chat-widget embed snippets by design) can obtain the remaining identifiers and exploit CVE-2026-71962 end-to-end without any out-of-band information.\n\n## 5. Impact\n\n- **Confidentiality (High):** Disclosure of user-uploaded and AI/tool-generated files belonging to any chatflow on the instance \u2014 including private, non-public chatflows in other workspaces/organizations \u2014 without any credentials, once the target's identifier tuple is known (Section 3.7).\n- **Scope:** Because `getFileFromAssistant` resolves the target organization/workspace from the *supplied* `chatflowId` rather than from the requester, the tenant-isolation boundary for file storage provides no protection against this endpoint on any multi-tenant deployment (Flowise Cloud, or self-hosted instances serving multiple organizations/workspaces).\n- **Attack complexity \u2014 CVSS rationale:** Once a target file's `chatflowId`/`chatId`/`fileName` tuple is known, exploitation requires exactly one unauthenticated HTTP request, with no race condition, no brute-forcing or guessing of the identifiers, no cryptographic bypass, no path traversal or UUID-validation bypass (Section 3.5), and no unusual or rare deployment condition. Section 4.4 additionally demonstrates a fully self-contained, unauthenticated identifier-acquisition chain requiring only a `chatflowId` to start.\n\n## 6. Suggested Remediation\n\n*Illustrative remediation based on the membership pattern already used by `getSinglePublicChatflow` \u2014 not a compile-tested, drop-in patch.* Apply the same authorization gate already used elsewhere in the codebase to `getFileFromAssistant`. Note this deliberately checks **workspace membership**, not merely the requester's *currently active* workspace (`req.user.activeWorkspaceId`):\n```ts\nconst chatflow = await appServer.AppDataSource.getRepository(ChatFlow).findOneBy({ id: chatflowId })\nif (!chatflow) throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Chatflow ${chatflowId} not found`)\n\nif (!chatflow.isPublic) {\n    if (!req.user) return res.status(StatusCodes.UNAUTHORIZED).json({ message: 'Unauthorized' })\n\n    const workspaceUser = await workspaceUserService.readWorkspaceUserByUserId(req.user.id, queryRunner)\n    const workspaceIds = workspaceUser.map((wu) =&gt; wu.workspaceId)\n    if (!workspaceIds.includes(chatflow.workspaceId)) {\n        return res.status(StatusCodes.FORBIDDEN).json({ message: 'Forbidden' })\n    }\n}\n```\nSuggested status-code convention: `401` when no valid credentials are presented at all, `403` once authenticated but lacking the required workspace membership. As defense in depth, consider binding `chatId` to a server-issued, per-session token rather than trusting a bare client-supplied UUID, even for legitimately public chatflows. The same fix should be applied to `GET /api/v1/feedback/:chatflowId` (Section 4.4).\n\n## 7. Prior Art / Duplicate Check\n\nCross-referenced against all publicly indexed Flowise CVEs and GitHub Security Advisories as of 2026-08-09 that relate to this endpoint or file-storage authorization in general:\n\n| Advisory | Endpoint | Root cause | Relation to this report |\n|---|---|---|---|\n| GHSA-99pg-hqvx-r4gf | same endpoint | Path traversal via unvalidated `chatId` (reads `database.sqlite`) | Different defect, fixed in 3.0.6; traversal guard confirmed present and effective in the version tested here |\n| GHSA-q67q-549q-p849 | same endpoint + `get-upload-file` | Path traversal, `chatflowId` not UUID-validated | Different defect, fixed in 3.0.6 |\n| CVE-2026-67622 | `openai-assistants` (list/retrieve) | Confused-deputy via client-controlled `credential` UUID | Different endpoint and mechanism \u2014 uses OpenAI's own API via a stolen credential reference |\n| CVE-2026-70472 | `openai-assistants-vector-store` | Same credential-UUID confused-deputy pattern | Different endpoint/mechanism |\n| CVE-2026-69252 | `/api/v1/files` (GET/DELETE) | Missing `checkPermission` for authenticated API-key callers | Different endpoint; requires a valid API key (`PR:L`), this finding requires none (`PR:N`) |\n| CVE-2026-70473 | `/upsert-history` | Unscoped, server-wide history disclosure | Different endpoint/data class |\n\nNo existing advisory describes a missing-`isPublic`/ownership check on `openai-assistants-file/download` distinct from the path-traversal issue. A relevant architectural precedent is CVE-2026-69258 (`POST /api/v1/prediction/:id`, also whitelisted by design, CVSS 8.2) \u2014 an intentionally public/whitelisted endpoint later found to have a specific, narrower authorization gap within that intended public surface, similar in shape to the finding reported here.\n\n## 8. Disclosure Timeline\n\n- **2026-08-09** \u2014 Vulnerability identified via source review of the official `flowise@3.1.4` release tag.\n- **2026-08-09** \u2014 Live-reproduced end-to-end against a Docker build of the same tag.\n- **2026-08-09** \u2014 Reported to VulnCheck (disclosures@vulncheck.com).\n- **2026-08-10** \u2014 VulnCheck confirmed and reserved **CVE-2026-71962**.\n- **Vendor status:** FlowiseAI/Flowise's `SECURITY.md` states the project is being sunset and is no longer accepting new vulnerability reports; the repository was scheduled for GitHub archival (2026-08-10 per the project's published sunset notice: https://flowiseai.com/sunset). Standard vendor-coordinated disclosure via GitHub Security Advisories was therefore not available, and this report was submitted through VulnCheck as a CVE Numbering Authority that does not require vendor participation.\n\n## 9. Credit\n\nDiscovered and reported by **Mai Hai Dang** (haidang.infosec@gmail.com).", "creation_timestamp": "2026-08-10T17:18:10.195435Z"}, {"uuid": "192a2c46-8049-4589-96db-3f9e8d9aa518", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-69252", "type": "seen", "source": "https://gist.github.com/haidang-infosec/402db84bee7aca2f57bb109b31574649", "content": "# CVE-2026-71962: Unauthenticated Cross-Tenant File Disclosure in Flowise via `openai-assistants-file/download`\n\n**CVE ID:** CVE-2026-71962\n**CNA:** VulnCheck\n**Author:** Mai Hai Dang (haidang.infosec@gmail.com)\n**Report date:** 2026-08-09\n**Product:** Flowise ([FlowiseAI/Flowise](https://github.com/FlowiseAI/Flowise), npm package `flowise`)\n**Affected component:** `packages/server` \u2014 REST API\n**Vulnerability class:** Missing Authorization / Insecure Direct Object Reference (IDOR)\n**CWE:** CWE-862 (Missing Authorization) \u2014 primary; CWE-639 (Authorization Bypass Through User-Controlled Key) \u2014 secondary\n**CVSS 3.1:** `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N` \u2014 **7.5 (High)**\n**CVSS 4.0:** `CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N` \u2014 **8.7 (High)**\n\n---\n\n## 1. Summary\n\nThe Flowise REST API endpoint `POST /api/v1/openai-assistants-file/download` is served without any authentication check \u2014 it is listed in the server's global `WHITELIST_URLS`, which bypasses both session-cookie and API-key authentication for any request whose path matches it. The handler behind this endpoint (`getFileFromAssistant`) resolves and streams a file from the server's file storage (local disk or S3, depending on deployment) using three client-supplied identifiers \u2014 `chatflowId`, `chatId`, `fileName` \u2014 without ever verifying that the target chatflow is public (`isPublic: true`) or that the requester belongs to the workspace that owns it.\n\nAn unauthenticated requester who knows a valid `chatflowId`/`chatId`/`fileName` tuple can retrieve the corresponding stored file without any authentication or workspace-membership check. This was directly reproduced against a private chatflow (Section 4). Cross-workspace/cross-organization impact is not separately runtime-tested with two tenants, but follows directly from the handler's data flow: `getFileFromAssistant` resolves the owning workspace and organization from the *supplied* `chatflowId` alone (Section 3.3) and never evaluates the requester's identity, so the same zero-authentication request works identically regardless of which workspace or organization the target chatflow belongs to.\n\nThis is a distinct defect from the previously disclosed and patched path-traversal vulnerabilities affecting the same endpoint (GHSA-99pg-hqvx-r4gf, GHSA-q67q-549q-p849); those were fixed by adding strict path-traversal validation to `chatflowId`/`chatId`/`fileName`, which is confirmed present and effective in the version tested. The defect reported here is a pure authorization gap: the request never leaves the *intended* storage path, it simply is never checked for ownership.\n\n## 2. Affected Versions\n\n| Scope | Status |\n|---|---|\n| npm `flowise` `3.1.4` (latest published release, git tag `flowise@3.1.4` = commit `a65f81bb`, 2026-07-29) | Confirmed by runtime reproduction (Section 4) |\n| Current public GitHub `main` branch HEAD | Confirmed by source inspection (code path unchanged relative to `3.1.4`) |\n| npm `flowise` `2.2.4` \u2013 `3.1.3` | Presumed affected, based on `git log`/`git blame` showing the vulnerable code has been present, unmodified, since `2.2.4`; not individually runtime-tested per version |\n\nThe PoC in this report was reproduced by checking out the official release tag directly (`git checkout flowise@3.1.4`), removing any ambiguity about whether the finding applies to unreleased code.\n\n**Version history (established via `git log`/`git blame` against the public repository):**\n- The `WHITELIST_URLS` entry for this exact path was introduced in commit `8d266052` (\"Feature/update upsert API\"), dated 2025-01-09, first shipped in release `2.2.4`. `git log -S` against the literal route string shows this is the only commit that has ever touched it \u2014 it has never been removed or narrowed.\n- The `getFileFromAssistant` handler has never, at any point in its history, contained an `isPublic`, `req.user`, or workspace-membership check (`git log -S\"isPublic\"` on the controller file returns zero matches).\n- The most recent related fix in this file, commit `0b74fc07` (\"fix: flowise-603\", 2026-08-07 \u2014 the fix for the previously reported CVE-2026-67622 credential-confused-deputy issue), added workspace scoping to three sibling handlers in the same file (`getAllOpenaiAssistants`, `getSingleOpenaiAssistant`, `uploadAssistantFiles`) but did not touch `getFileFromAssistant`.\n\n## 3. Technical Details\n\n### 3.1 Authentication bypass (whitelist)\n\n`packages/server/src/utils/constants.ts`:\n```ts\nexport const WHITELIST_URLS = [\n    ...\n    '/api/v1/openai-assistants-file/download',\n    ...\n]\n```\n\n`packages/server/src/index.ts` (global auth middleware):\n```ts\nconst isWhitelisted = whitelistURLs.some((url) =&gt; req.path.startsWith(url))\nif (isWhitelisted) {\n    next()   // skips verifyToken() (session/JWT) and validateAPIKey() entirely\n}\n```\n\n### 3.2 Route has no permission middleware\n\n`packages/server/src/routes/openai-assistants-files/index.ts` \u2014 contrast with the sibling `upload/` route on the same router, which *does* enforce RBAC:\n```ts\nrouter.post('/download/', openaiAssistantsController.getFileFromAssistant)\n\nrouter.post(\n    '/upload/',\n    checkAnyPermission('assistants:create,assistants:update'),\n    getMulterStorage().array('files'),\n    openaiAssistantsController.uploadAssistantFiles\n)\n```\n\n### 3.3 Controller performs no ownership check\n\n`packages/server/src/controllers/openai-assistants/index.ts`, `getFileFromAssistant`:\n```ts\nconst getFileFromAssistant = async (req: Request, res: Response, next: NextFunction) =&gt; {\n    const chatflowId = req.body.chatflowId as string\n    const chatId = req.body.chatId as string\n    const fileName = req.body.fileName as string\n\n    // \"This can be public API, so we can only get orgId from the chatflow\"\n    const chatflow = await appServer.AppDataSource.getRepository(ChatFlow).findOneBy({ id: chatflowId })\n    // no isPublic check\n    // no req.user / workspace check\n\n    const orgId = workspace.organizationId as string\n    res.setHeader('Content-Disposition', contentDisposition(fileName))\n    const fileStream = await streamStorageFile(chatflowId, chatId, fileName, orgId)\n    fileStream.pipe(res)\n}\n```\n\nThe comment in the source (`\"This can be public API...\"`) shows the author was aware this handler must operate without `req.user`, but never added the corresponding public/private gate.\n\n### 3.4 The codebase's own correct pattern for this exact situation\n\n`packages/server/src/controllers/chatflows/index.ts`, `getSinglePublicChatflow` \u2014 the pattern that should have been applied to `getFileFromAssistant`:\n```ts\nconst chatflow = await chatflowsService.getChatflowById(req.params.id)\nif (!chatflow) return res.status(404).json({ message: 'Chatflow not found' })\nif (chatflow.isPublic)\n    return res.status(200).json({ ...chatflow, flowData: sanitizeFlowDataForPublicEndpoint(chatflow.flowData) })\nif (!req.user) return res.status(401).json({ message: 'Unauthorized' })\nif (!workspaceIds.includes(chatflow.workspaceId))\n    return res.status(400).json({ message: 'You are not in the workspace that owns this chatflow' })\n```\nThis is the exact three-step check \u2014 (1) `chatflow.isPublic`, (2) `req.user` presence, (3) `workspaceIds.includes(chatflow.workspaceId)` \u2014 that `getFileFromAssistant` omits entirely. Its presence elsewhere in the same codebase demonstrates this is an oversight, not an intentional design decision.\n\n### 3.5 Ruled out: this is not a path-traversal bug\n\n`packages/components/src/storage/BaseStorageProvider.ts` (`sanitizeFilename`, `validatePathSecurity`) and `LocalStorageProvider.streamStorageFile` validate all three path components and reject `..`/absolute-path escape attempts before touching the filesystem. This closes off the vector exploited by the previously fixed GHSA-99pg-hqvx-r4gf / GHSA-q67q-549q-p849. The finding in this report requires no traversal \u2014 it retrieves a file from exactly the path the application itself would use, for a resource the caller has no authorization to access.\n\n### 3.6 Legitimate file-creation path (storage layout is not test-only)\n\nThe PoC in Section 4 places the victim file directly on disk as a deterministic test fixture rather than through a real chat interaction. This section establishes that the fixture's location is not artificial: it is exactly the layout Flowise's own, ordinary chat-attachment upload workflow writes to.\n\n`packages/server/src/utils/buildChatflow.ts`, in the request-handling path for chat messages that include file/image/audio uploads (`uploads`), including on public-facing chatflows with no authentication required to converse:\n```ts\nconst { totalSize } = await addSingleFileToStorage(mime, bf, filename, orgId, chatflowid, chatId)\n```\n`addSingleFileToStorage(mime, buffer, filename, orgId, chatflowid, chatId)` writes to `////` \u2014 the identical path structure `streamStorageFile` reads from in the vulnerable handler (Section 3.3):\n```\nLegitimate file creation:                     Vulnerable retrieval:\nbuildChatflow.ts (chat upload handling)       getFileFromAssistant()\n  -&gt; addSingleFileToStorage(                    -&gt; streamStorageFile(\n      mime, buffer, filename,                       chatflowId, chatId,\n      orgId, chatflowid, chatId)                     fileName, orgId)\n  -&gt; writes ///  -&gt; reads the same path\n```\nThe file in the PoC was placed directly only to create a deterministic test fixture; its path and naming layout exactly match the storage layout produced by this legitimate, unauthenticated-reachable upload workflow.\n\n### 3.7 Identifier exposure and attack prerequisites\n\nThe identifiers consumed by the vulnerable endpoint \u2014 `chatflowId`, `chatId`, `fileName` \u2014 are ordinary client-side resource locators, not authorization credentials or server-issued capability tokens:\n\n- `chatId` is generated client-side (`const [chatId, setChatId] = useState(uuidv4())`, `packages/ui/src/views/chatmessage/ChatMessage.jsx:213`) and persisted via `localStorage.setItem` (`packages/ui/src/utils/genericHelper.js:889`, `setLocalStorageChatflow`) \u2014 it is never issued or cryptographically bound to a session by the server.\n- The official frontend embeds `chatflowId`, `chatId`, and `fileName` directly, in plaintext, in file URLs it renders in the chat UI, e.g. `${baseURL}/api/v1/get-upload-file?chatflowId=${chatflowid}&amp;chatId=${chatId}&amp;fileName=${...}` (`ChatMessage.jsx:719, 1338, 1349`).\n\n`chatId` is not an authorization credential and is not cryptographically bound to the requester's identity or session. Consequently, possession of a `chatflowId`/`chatId`/`fileName` tuple must not be treated by the server as proof of authorization \u2014 yet `getFileFromAssistant` treats it as sufficient. Because these values are exposed to the browser DOM and network layer by ordinary use of the product, they may consequently appear in client-side logs, reverse-proxy or gateway logs, monitoring/APM systems, shared HTML, or diagnostic material such as exported conversations or bug reports.\n\n**What this evidence does *not* establish:** observing that identifiers for a given (e.g. public) chatflow are exposed in that chatflow's own UI does not by itself demonstrate that an attacker can obtain the tuple for an *arbitrary, unrelated private* target chatflow. This report does not claim that. The exploitation prerequisite is stated precisely as:\n\n&gt; Exploitation requires knowledge of the exact `chatflowId`/`chatId`/`fileName` tuple for the target file. This report does not rely on guessing, brute-forcing, path traversal, or bypassing UUID validation to obtain that tuple \u2014 Section 3.5 confirms no traversal path exists, and none is needed once the tuple is known. How a specific attacker obtains a specific target's tuple is scenario-dependent and outside the scope of this report; the defect is that the server performs no authorization check at all once the tuple is presented, regardless of how it was obtained.\n\n## 4. Proof of Concept\n\nReproduced end-to-end against the **official `flowise@3.1.4` release tag**, built and run via the project's own `Dockerfile` (`docker build -t flowise-local:3.1.4 .`), default configuration (local file storage, SQLite).\n\n**Scope of this PoC:** the following is directly reproduced against a single private chatflow within a single organization/workspace \u2014 a second tenant was not separately stood up. Cross-workspace/cross-organization impact is established by the handler's own logic, not by this specific run (see Section 1).\n\n### 4.1 Setup\n\n1. Created a workspace-owner account via the normal setup UI.\n2. `POST /api/v1/chatflows`, authenticated, `isPublic: false` \u2014 created the private target chatflow (`id = 3055de1b-586b-4756-9e77-da2c19b62f95`, `workspaceId = 53141120-b356-452a-b34d-28549fdbab9d`, `organizationId = b2439594-7c21-4bf7-86b6-b1d90ffd40b8`).\n3. A file was placed at the exact path the application itself uses for chat-generated/uploaded files \u2014 `////` \u2014 as a deterministic test fixture matching the legitimate upload workflow traced in Section 3.6.\n\n### 4.2 Request A \u2014 Control\n\nSent with **no** `Cookie`/`Authorization` header, targeting the equivalent metadata-read endpoint for the same resource:\n```\nGET /api/v1/chatflows/3055de1b-586b-4756-9e77-da2c19b62f95 HTTP/1.1\nHost: localhost:3000\n```\n**Response:** `HTTP/1.1 401 Unauthorized`\n```json\n{\"message\":\"Invalid or Missing token\"}\n```\nThis confirms the platform *does* enforce authentication on the equivalent, properly-guarded endpoint for the identical resource.\n\n### 4.3 Request B \u2014 Exploit\n\nSent with **no** `Cookie`/`Authorization` header at all, against the vulnerable endpoint:\n```\nPOST /api/v1/openai-assistants-file/download HTTP/1.1\nHost: localhost:3000\nContent-Type: application/json\nContent-Length: 123\n\n{\"chatflowId\":\"3055de1b-586b-4756-9e77-da2c19b62f95\",\"chatId\":\"e29b8f3a-victim-chat-01\",\"fileName\":\"secret-report.txt\"}\n```\n**Response:** `HTTP/1.1 200 OK`\n```\nContent-Disposition: attachment; filename=\"secret-report.txt\"\n\nCONFIDENTIAL - victim workspace uploaded file - should NOT be downloadable without auth\n```\n\nRequest A (targeting the exact same private resource, via the properly-guarded metadata endpoint) was correctly rejected; Request B (targeting the file-download endpoint) was not \u2014 isolating the defect to this specific handler rather than a global authentication failure.\n\n### 4.4 Additional confirmation \u2014 full unauthenticated identifier-acquisition chain\n\nIn a related finding against the same instance, the sibling whitelisted endpoint `GET /api/v1/feedback/:chatflowId` (`packages/server/src/controllers/feedback/index.ts`, `packages/server/src/utils/getChatMessageFeedback.ts`) was found to return `ChatMessageFeedback` records \u2014 including the real `chatId` for the chatflow \u2014 for **any** `chatflowId`, with the same missing-authorization pattern and no additional identifiers required:\n```\nGET /api/v1/feedback/3055de1b-586b-4756-9e77-da2c19b62f95 HTTP/1.1\nHost: localhost:3000\n```\n```json\n[{\"id\":\"...\",\"chatflowid\":\"3055de1b-...\",\"chatId\":\"e29b8f3a-victim-chat-01\",\"messageId\":\"...\",\"rating\":\"THUMBS_DOWN\",\"content\":\"...\",\"createdDate\":\"...\"}]\n```\nThe `chatId` returned by this unauthenticated request was then used, unmodified, in Request B above and successfully retrieved the file \u2014 demonstrating that an attacker starting with **only a `chatflowId`** (routinely exposed in public chat-widget embed snippets by design) can obtain the remaining identifiers and exploit CVE-2026-71962 end-to-end without any out-of-band information.\n\n## 5. Impact\n\n- **Confidentiality (High):** Disclosure of user-uploaded and AI/tool-generated files belonging to any chatflow on the instance \u2014 including private, non-public chatflows in other workspaces/organizations \u2014 without any credentials, once the target's identifier tuple is known (Section 3.7).\n- **Scope:** Because `getFileFromAssistant` resolves the target organization/workspace from the *supplied* `chatflowId` rather than from the requester, the tenant-isolation boundary for file storage provides no protection against this endpoint on any multi-tenant deployment (Flowise Cloud, or self-hosted instances serving multiple organizations/workspaces).\n- **Attack complexity \u2014 CVSS rationale:** Once a target file's `chatflowId`/`chatId`/`fileName` tuple is known, exploitation requires exactly one unauthenticated HTTP request, with no race condition, no brute-forcing or guessing of the identifiers, no cryptographic bypass, no path traversal or UUID-validation bypass (Section 3.5), and no unusual or rare deployment condition. Section 4.4 additionally demonstrates a fully self-contained, unauthenticated identifier-acquisition chain requiring only a `chatflowId` to start.\n\n## 6. Suggested Remediation\n\n*Illustrative remediation based on the membership pattern already used by `getSinglePublicChatflow` \u2014 not a compile-tested, drop-in patch.* Apply the same authorization gate already used elsewhere in the codebase to `getFileFromAssistant`. Note this deliberately checks **workspace membership**, not merely the requester's *currently active* workspace (`req.user.activeWorkspaceId`):\n```ts\nconst chatflow = await appServer.AppDataSource.getRepository(ChatFlow).findOneBy({ id: chatflowId })\nif (!chatflow) throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Chatflow ${chatflowId} not found`)\n\nif (!chatflow.isPublic) {\n    if (!req.user) return res.status(StatusCodes.UNAUTHORIZED).json({ message: 'Unauthorized' })\n\n    const workspaceUser = await workspaceUserService.readWorkspaceUserByUserId(req.user.id, queryRunner)\n    const workspaceIds = workspaceUser.map((wu) =&gt; wu.workspaceId)\n    if (!workspaceIds.includes(chatflow.workspaceId)) {\n        return res.status(StatusCodes.FORBIDDEN).json({ message: 'Forbidden' })\n    }\n}\n```\nSuggested status-code convention: `401` when no valid credentials are presented at all, `403` once authenticated but lacking the required workspace membership. As defense in depth, consider binding `chatId` to a server-issued, per-session token rather than trusting a bare client-supplied UUID, even for legitimately public chatflows. The same fix should be applied to `GET /api/v1/feedback/:chatflowId` (Section 4.4).\n\n## 7. Prior Art / Duplicate Check\n\nCross-referenced against all publicly indexed Flowise CVEs and GitHub Security Advisories as of 2026-08-09 that relate to this endpoint or file-storage authorization in general:\n\n| Advisory | Endpoint | Root cause | Relation to this report |\n|---|---|---|---|\n| GHSA-99pg-hqvx-r4gf | same endpoint | Path traversal via unvalidated `chatId` (reads `database.sqlite`) | Different defect, fixed in 3.0.6; traversal guard confirmed present and effective in the version tested here |\n| GHSA-q67q-549q-p849 | same endpoint + `get-upload-file` | Path traversal, `chatflowId` not UUID-validated | Different defect, fixed in 3.0.6 |\n| CVE-2026-67622 | `openai-assistants` (list/retrieve) | Confused-deputy via client-controlled `credential` UUID | Different endpoint and mechanism \u2014 uses OpenAI's own API via a stolen credential reference |\n| CVE-2026-70472 | `openai-assistants-vector-store` | Same credential-UUID confused-deputy pattern | Different endpoint/mechanism |\n| CVE-2026-69252 | `/api/v1/files` (GET/DELETE) | Missing `checkPermission` for authenticated API-key callers | Different endpoint; requires a valid API key (`PR:L`), this finding requires none (`PR:N`) |\n| CVE-2026-70473 | `/upsert-history` | Unscoped, server-wide history disclosure | Different endpoint/data class |\n\nNo existing advisory describes a missing-`isPublic`/ownership check on `openai-assistants-file/download` distinct from the path-traversal issue. A relevant architectural precedent is CVE-2026-69258 (`POST /api/v1/prediction/:id`, also whitelisted by design, CVSS 8.2) \u2014 an intentionally public/whitelisted endpoint later found to have a specific, narrower authorization gap within that intended public surface, similar in shape to the finding reported here.\n\n## 8. Disclosure Timeline\n\n- **2026-08-09** \u2014 Vulnerability identified via source review of the official `flowise@3.1.4` release tag.\n- **2026-08-09** \u2014 Live-reproduced end-to-end against a Docker build of the same tag.\n- **2026-08-09** \u2014 Reported to VulnCheck (disclosures@vulncheck.com).\n- **2026-08-10** \u2014 VulnCheck confirmed and reserved **CVE-2026-71962**.\n- **Vendor status:** FlowiseAI/Flowise's `SECURITY.md` states the project is being sunset and is no longer accepting new vulnerability reports; the repository was scheduled for GitHub archival (2026-08-10 per the project's published sunset notice: https://flowiseai.com/sunset). Standard vendor-coordinated disclosure via GitHub Security Advisories was therefore not available, and this report was submitted through VulnCheck as a CVE Numbering Authority that does not require vendor participation.\n\n## 9. Credit\n\nDiscovered and reported by **Mai Hai Dang** (haidang.infosec@gmail.com).", "creation_timestamp": "2026-08-10T17:18:10.248208Z"}, {"uuid": "7243e21b-4ea6-43c4-933f-8869a443173d", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "86ecb4e1-bb32-44d5-9f39-8a4673af8385", "vulnerability": "CVE-2026-69256", "type": "seen", "source": "https://www.acn.gov.it/portale/w/aggiornamenti-di-sicurezza-per-flowise", "content": "", "creation_timestamp": "2026-08-06T20:45:19.112883Z"}, {"uuid": "be2534a6-e00b-4adb-ab7e-9629f8407bb3", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "86ecb4e1-bb32-44d5-9f39-8a4673af8385", "vulnerability": "CVE-2026-69257", "type": "seen", "source": "https://www.acn.gov.it/portale/w/aggiornamenti-di-sicurezza-per-flowise", "content": "", "creation_timestamp": "2026-08-06T20:45:16.869644Z"}, {"uuid": "4a525c38-2171-489c-aabe-507656566843", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "86ecb4e1-bb32-44d5-9f39-8a4673af8385", "vulnerability": "CVE-2026-69255", "type": "seen", "source": "https://www.acn.gov.it/portale/w/aggiornamenti-di-sicurezza-per-flowise", "content": "", "creation_timestamp": "2026-08-06T20:45:21.365798Z"}, {"uuid": "749b5dcc-183a-432f-a010-d6886f6ec811", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "86ecb4e1-bb32-44d5-9f39-8a4673af8385", "vulnerability": "CVE-2026-69259", "type": "seen", "source": "https://www.acn.gov.it/portale/w/aggiornamenti-di-sicurezza-per-flowise", "content": "", "creation_timestamp": "2026-08-06T20:45:37.365975Z"}, {"uuid": "ace49541-1455-4cb8-8d6e-3d592af8242e", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "86ecb4e1-bb32-44d5-9f39-8a4673af8385", "vulnerability": "CVE-2026-69258", "type": "seen", "source": "https://www.acn.gov.it/portale/w/aggiornamenti-di-sicurezza-per-flowise", "content": "", "creation_timestamp": "2026-08-06T20:45:39.608944Z"}, {"uuid": "328f5b62-1c46-444b-840c-2eca171278f8", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-69250", "type": "published-proof-of-concept", "source": "https://t.me/bdufstecru/3366", "content": "\u0423\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u044c \u0444\u0430\u0439\u043b\u0430 dist/routes/oauth2/index.js \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u0432 \u043f\u043e\u0432\u0435\u0440\u0445 \u044f\u0437\u044b\u043a\u043e\u0432\u044b\u0445 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 (LLM) Flowise \u0441\u0432\u044f\u0437\u0430\u043d\u0430 \u0441 \u043e\u0431\u0445\u043e\u0434\u043e\u043c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c \u043a\u043b\u044e\u0447\u0430, \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c. \u042d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0430\u0446\u0438\u044f \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0438 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442\u044c \u043d\u0430\u0440\u0443\u0448\u0438\u0442\u0435\u043b\u044e, \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c\u0443 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e, \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0438\u0442\u044c SSRF-\u0430\u0442\u0430\u043a\u0443 \u0438 \u0440\u0430\u0441\u043a\u0440\u044b\u0442\u044c \u0437\u0430\u0449\u0438\u0449\u0430\u0435\u043c\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e\n\nBDU:2026-11135\nCVE-2026-69250\n\n\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0439 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044f:\nhttps://github.com/FlowiseAI/Flowise/commit/da8b251a9a4c59484ceaf6f71df7406aede7bef2", "creation_timestamp": "2026-08-07T14:03:17.147770Z"}, {"uuid": "72368b0b-28d0-49a3-b139-8fa5f5024c87", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-69258", "type": "seen", "source": "https://bsky.app/profile/hacker.at.thenote.app/post/3muep7yrslk25", "content": "The Spread Operator Is an Allowlist With Nothing In It: CVE-2026-69258 in Flowise\n\nCVE-2026-69258: two ungated spread operators let an unauthenticated caller write into the flow execution context of any public Flowise chatflow.\n#hackernews #news", "creation_timestamp": "2026-08-31T10:30:53.504218Z"}, {"uuid": "43dd8979-1dc0-44a8-8d83-b719dae847a5", "vulnerability_lookup_origin": "caeb2787-0d58-4236-9039-7c86c3e566f3", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-69255", "type": "exploited", "source": "https://vulnerability.circl.lu/known-exploited-vulnerabilities-catalog/b21ce316-7de6-4bbc-8d24-5dc1e3a0f2fb", "content": "", "creation_timestamp": "2026-09-16T20:00:44.470411Z"}]}