{"record":{"id":"f8617774e51ac9e8","repo":"ruvnet/ruflo","slug":"label-escapes-project-directory","errorCode":null,"errorMessage":"${label} escapes project directory","messagePattern":"(.+?) escapes project directory","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/commands/daemon.ts","lineNumber":385,"sourceCode":"  // Must be absolute after resolution\n  const resolved = resolve(path);\n\n  // Check for null bytes (injection attack)\n  if (path.includes('\\0')) {\n    throw new Error(`${label} contains null bytes`);\n  }\n\n  // Check for shell metacharacters in path components\n  if (/[;&|`$<>]/.test(path)) {\n    throw new Error(`${label} contains shell metacharacters`);\n  }\n\n  // Prevent path traversal outside expected directories\n  if (!resolved.includes('.claude-flow') && !resolved.includes('bin')) {\n    // Allow only paths within project structure\n    const cwd = process.cwd();\n    if (!resolved.startsWith(cwd)) {\n      throw new Error(`${label} escapes project directory`);\n    }\n  }\n}\n\n/**\n * #1914: Resolve the `--workspace` flag to an absolute path, or return null\n * if it is absent / not a usable string. Rejects values with null bytes or\n * shell metacharacters (defence-in-depth — the value is later embedded in a\n * forked child's argv and compared against `ps`/`tasklist` output).\n */\nexport function resolveWorkspaceFlag(raw: unknown): string | null {\n  if (typeof raw !== 'string') return null;\n  const trimmed = raw.trim();\n  if (!trimmed) return null;\n  if (trimmed.includes('\\0') || /[;&|`$<>]/.test(trimmed)) return null;\n  return resolve(trimmed);\n}\n","sourceCodeStart":367,"sourceCodeEnd":403,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/commands/daemon.ts#L367-L403","documentation":"Thrown by validatePath() in the daemon command when the resolved absolute path is neither under the current working directory nor inside a directory whose resolved path contains '.claude-flow' or 'bin'. The guard prevents path traversal: daemon paths are expected to stay within the project or the tool's own layout directories.","triggerScenarios":"Running `claude-flow daemon start --workspace /tmp/scratch` from ~/repo (path is outside cwd and has no .claude-flow/bin segment), passing a relative path like ../../elsewhere that resolves outside cwd, or invoking the CLI from a different directory than the project.","commonSituations":"cd'ed into the wrong directory before running the command; pointing the workspace at a shared absolute path (/var/lib/...); containers or symlinks where process.cwd() differs from where the project actually lives.","solutions":["cd into the project root first so the resolved workspace starts with process.cwd()","Use a workspace under <project>/.claude-flow — the '.claude-flow' path segment is whitelisted","If the path targets a binary, keep it in a directory whose resolved path contains 'bin'","Verify what the path resolves to: node -e \"console.log(require('path').resolve(process.argv[1]))\" <your-path>"],"exampleFix":"# before (run from ~/other)\nclaude-flow daemon start --workspace /home/me/repo/data\n\n# after\ncd /home/me/repo && claude-flow daemon start --workspace /home/me/repo/.claude-flow","handlingStrategy":"validation","validationCode":"import { resolve } from 'node:path';\nfunction isInsideProject(p: string): boolean {\n  const r = resolve(p);\n  return r.includes('.claude-flow') || r.includes(`${resolve('bin')}`) || r.startsWith(process.cwd());\n}\nif (!isInsideProject(workspace)) workspace = resolve(process.cwd(), '.claude-flow');","typeGuard":null,"tryCatchPattern":"try {\n  await cli.daemon.start({ workspace });\n} catch (err) {\n  if (err instanceof Error && err.message.endsWith('escapes project directory')) {\n    // re-run from the project root or point the path under <project>/.claude-flow\n  } else throw err;\n}","preventionTips":["Always run daemon commands from the project root","Default workspaces to <projectRoot>/.claude-flow in wrappers","Resolve relative paths against the project root before passing them"],"tags":["cli","daemon","path-traversal","workspace","security"],"backgroundTag":"path-traversal-blocked","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}