{"record":{"id":"c6fb526a7ec890f3","repo":"ruvnet/ruflo","slug":"label-contains-shell-metacharacters","errorCode":null,"errorMessage":"${label} contains shell metacharacters","messagePattern":"(.+?) contains shell metacharacters","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/commands/daemon.ts","lineNumber":377,"sourceCode":"    }\n  },\n};\n\n/**\n * Validate path for security - prevents path traversal and injection\n */\nfunction validatePath(path: string, label: string): void {\n  // 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 */","sourceCodeStart":359,"sourceCodeEnd":395,"githubUrl":"https://github.com/ruvnet/ruflo/blob/6b01dc5a687b26b3e218f796de45ec51f8fa9e8c/v3/@claude-flow/cli/src/commands/daemon.ts#L359-L395","documentation":"Thrown by the internal validatePath() function in daemon.ts when a path contains shell metacharacters: semicolon (;), ampersand (&), pipe (|), backtick (`), dollar sign ($), or angle brackets (< >). These characters could enable command injection if the path is ever interpolated into a shell command, even though the current code paths use execFileSync (no shell on POSIX). This is defence-in-depth.","triggerScenarios":"A path string passed to validatePath() matches the regex /[;&|`$<>]/. For example, a workspace path like '/tmp/proj;rm -rf /' or '/var/$HOME/app'.","commonSituations":"A path was constructed from untrusted user input without sanitization; an environment variable containing shell expansions was used as a path; a test deliberately included metacharacters to exercise the validator.","solutions":["Remove shell metacharacters (;, &, |, `, $, <, >) from the path","Use absolute paths that do not require shell expansion","If the path legitimately contains '$', expand environment variables before passing to validatePath"],"exampleFix":"// before\nconst path = '/tmp/$USER/workspace;whoami';\nvalidatePath(path, 'workspace');\n\n// after\nconst user = process.env.USER || 'default';\nconst path = `/tmp/${user}/workspace`;\nvalidatePath(path, 'workspace');","handlingStrategy":"validation","validationCode":"const SHELL_META_RE = /[;&|`$<>]/;\nfunction isShellSafePath(path: string): boolean {\n  return !SHELL_META_RE.test(path);\n}\n\nif (!isShellSafePath(userPath)) {\n  throw new Error('Path contains shell metacharacters');\n}","typeGuard":"function isShellSafe(s: string): boolean {\n  return !/[;&|`$<>]/.test(s);\n}","tryCatchPattern":"try {\n  validatePath(userPath, 'workspace');\n} catch (e) {\n  if (e instanceof Error && e.message.includes('shell metacharacters')) {\n    // Expand env vars manually, then strip metacharacters\n    userPath = userPath.replace(/\\$\\w+/g, (_, v) => process.env[v] || '');\n    // Retry\n  }\n}","preventionTips":["Expand environment variables before passing paths to the daemon","Avoid paths containing ;, &, |, `, $, <, or >","Use resolveWorkspaceFlag() for --workspace values — it already rejects shell metacharacters"],"tags":["security","shell-injection","metacharacters","daemon","path-traversal"],"backgroundTag":null,"analyzedSha":"6b01dc5a687b26b3e218f796de45ec51f8fa9e8c","analyzedAt":"2026-08-12T13:20:50.148Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}