| Title | Mintplex-Labs anything-llm < 1.12.1 Path Traversal |
|---|
| Description | AgentFlows.loadFlow() builds the target file path by joining the user-supplied uuid into the path first and only then normalizing it:
const flowJsonPath = normalizePath(path.join(AgentFlows.flowsDir, `${uuid}.json`));
normalizePath() is designed to strip traversal sequences, but it does so with a regex that only removes ../ occurrences at the start of the string:
function normalizePath(filepath = "") {
const result = path
.normalize(filepath.trim())
.replace(/^(\.\.(\/|\\|$))+/, "") // only strips LEADING ../
.trim();
if (["..", ".", "/"].includes(result)) throw new Error("Invalid path.");
return result;
}
Because the attacker-controlled uuid is concatenated behind the absolute flowsDir prefix, the string handed to normalizePath() never begins with ../. path.normalize() runs first and collapses the ../ segments against the flowsDir prefix, producing a path that has already escaped the intended directory. By the time the strip regex executes there is nothing left for it to match, so it is a no-op.
Critically, in the affected versions there is no containment check after normalization — the code only tests !uuid || !fs.existsSync(flowJsonPath). Both a file existence test and the subsequent fs.readFileSync() therefore operate on an arbitrary attacker-chosen path.
The identical flaw is present in AgentFlows.deleteFlow(), where the resulting path is passed to fs.rmSync(), giving arbitrary file deletion. |
|---|
| Source | ⚠️ https://github.com/zast-ai/vulnerability-reports/blob/main/anything-llm/path.md |
|---|
| User | ZAST.AI (UID 87884) |
|---|
| Submission | 09/29/2026 11:15 (25 days ago) |
|---|
| Moderation | 10/18/2026 10:30 (19 days later) |
|---|
| Status | Duplicate |
|---|
| VulDB entry | 355749 [mintplex-labs anything-llm up to 1.12.0 AgentFlows index.js loadFlow/deleteFlow path traversal] |
|---|
| Points | 0 |
|---|