{"record":{"id":"2b07a3590c914f5d","repo":"ruvnet/ruflo","slug":"unsafe-build-input-path-value","errorCode":null,"errorMessage":"unsafe build input path: ${value}","messagePattern":"unsafe build input path: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/codex/src/harness/build-evidence.ts","lineNumber":73,"sourceCode":"  if (!result) throw new Error(`${label} must be non-empty`);\n  return result;\n}\n\nfunction requireDigest(value: string, label: string): string {\n  if (!DIGEST.test(value)) throw new Error(`${label} must be a canonical sha256 digest`);\n  return value;\n}\n\nfunction normalizePath(value: string): string {\n  const path = requireText(value, 'build input path');\n  if (\n    path.includes('\\\\')\n    || path.startsWith('/')\n    || path.startsWith('-')\n    || path !== path.normalize('NFC')\n    || path.split('/').some((part) => !part || part === '.' || part === '..')\n  ) {\n    throw new Error(`unsafe build input path: ${value}`);\n  }\n  return path;\n}\n\nfunction sha256(value: string): string {\n  return `sha256:${createHash('sha256').update(value).digest('hex')}`;\n}\n\nfunction digestPath(path: string, followSymlink: boolean): { digest: string; bytes: number } {\n  const resolved = followSymlink ? realpathSync(path) : path;\n  const stat = lstatSync(resolved);\n  const content = stat.isSymbolicLink()\n    ? Buffer.from(readlinkSync(resolved), 'utf8')\n    : stat.isFile()\n      ? readFileSync(resolved)\n      : undefined;\n  if (!content) throw new Error(`build evidence path is not a file or symlink: ${path}`);\n  return {","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/codex/src/harness/build-evidence.ts#L55-L91","documentation":"normalizePath enforces a strict repository-relative POSIX shape for declared build input paths: no backslashes, no leading '/' (absolute) or '-', Unicode NFC normalization, and no empty, '.', or '..' segments. Any violation throws before the path is resolved or hashed. These rules keep declarations portable across platforms and prevent option-injection and traversal at digest time.","triggerScenarios":"A declared path containing a backslash ('dist\\app.js'), starting with '/' or '-', not in NFC form, or containing '', '.', or '..' segments such as 'src/./x', 'src/../x', 'src//x'.","commonSituations":"Feeding path.join/path.resolve output (absolute, platform separators) into declarations; copying paths from Windows shells; pasting macOS filenames (NFD-normalized) into configs; leaving a leading './' in generated paths.","solutions":["Declare plain relative POSIX paths from the repo root, e.g. 'dist/assets/manifest.json'","Strip leading './' and collapse '//', '.', and '..' segments before declaring","Normalize unicode once at the source: value.normalize('NFC')","Never pass path.resolve() or path.join() results directly — relativize against the repo root first"],"exampleFix":"// before\nconst inputs = [\n  { name: 'config', path: path.resolve(repoRoot, 'dist\\app.json') }, // absolute + backslash\n];\n\n// after\nconst inputs = [\n  { name: 'config', path: 'dist/app.json' },\n];","handlingStrategy":"validation","validationCode":"function isSafeRelativeInputPath(value: string): boolean {\n  return !value.includes('\\\\')\n    && !value.startsWith('/')\n    && !value.startsWith('-')\n    && value === value.normalize('NFC')\n    && value.split('/').every((part) => part && part !== '.' && part !== '..');\n}","typeGuard":"function isSafeRelativeInputPath(value: unknown): value is string {\n  return typeof value === 'string'\n    && !value.includes('\\\\')\n    && !value.startsWith('/')\n    && !value.startsWith('-')\n    && value === value.normalize('NFC')\n    && value.split('/').every((part) => part && part !== '.' && part !== '..');\n}","tryCatchPattern":null,"preventionTips":["Convert absolute paths to repo-relative with path.relative(repoRoot, abs) and POSIX separators before declaring","Normalize all declaration strings with .normalize('NFC') at ingest","Add a lint/test that greps declarations for backslashes and leading '-'"],"tags":["build-evidence","path-validation","harness","security","portability"],"backgroundTag":"unsafe-path-rejected","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}