{"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/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/commands/daemon.ts#L359-L395","documentation":"Thrown by validatePath() in the daemon command when a path argument (e.g. the --workspace flag) contains any of the shell metacharacters ; & | ` $ < >. The value is later embedded in a forked child's argv and compared against ps/tasklist output, so metacharacters are rejected as defence-in-depth against command injection. This is pure fail-fast input validation: the path is never used or written before the check.","triggerScenarios":"Invoking `claude-flow daemon ... --workspace '/tmp/my$dir'` (literal $ from an unexpanded variable), or any daemon path argument containing ;, &, |, a backtick, $, <, or >. Single-quoted shell arguments that keep $VAR unexpanded are the classic producer.","commonSituations":"CI systems that create directories containing $ (some runner temp dirs), paths copy-pasted from markdown wrapped in backticks, scripts that single-quote variables so they arrive literally, or test fixtures with shell-looking strings.","solutions":["Remove or rename path components containing ; & | ` $ < > — use plain alphanumerics, dashes, and underscores only","If the $ comes from an unexpanded variable, expand it before invoking the CLI (double quotes or interpolate the value yourself)","Pass a plain absolute path with no metacharacters, e.g. /home/user/project/.claude-flow","Do not look for an escape hatch — validatePath intentionally offers none; file an issue if the constraint is blocking"],"exampleFix":"# before\nclaude-flow daemon start --workspace '/opt/data$2026'\n\n# after\nclaude-flow daemon start --workspace '/opt/data-2026'","handlingStrategy":"validation","validationCode":"import { resolve } from 'node:path';\nfunction assertSafeDaemonPath(p: string, label = 'path'): void {\n  if (p.includes('\\0')) throw new Error(`${label}: null bytes`);\n  if (/[;&|`$<>]/.test(p)) throw new Error(`${label}: shell metacharacters not allowed`);\n}\nassertSafeDaemonPath(workspace); // before invoking the daemon command","typeGuard":"function isSafeDaemonPath(p: unknown): p is string {\n  return typeof p === 'string' && !p.includes('\\0') && !/[;&|`$<>]/.test(p);\n}","tryCatchPattern":"try {\n  await cli.daemon.start({ workspace });\n} catch (err) {\n  if (err instanceof Error && err.message.endsWith('contains shell metacharacters')) {\n    // reject/repair the path, then retry with a sanitized value\n  } else throw err;\n}","preventionTips":["Keep workspace and binary paths to alphanumerics, dashes, and underscores","Expand environment variables yourself before passing paths to the CLI","In test suites, assert isSafeDaemonPath() on any path built from templates"],"tags":["cli","daemon","path-validation","shell-injection","security"],"backgroundTag":"path-validation-failed","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"}