{"record":{"id":"d5169be407389b3f","repo":"ruvnet/ruflo","slug":"invalid-gcs-object-path-objectpath","errorCode":null,"errorMessage":"Invalid GCS object path: ${objectPath}","messagePattern":"Invalid GCS object path: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/transfer/storage/gcs.ts","lineNumber":133,"sourceCode":"  }\n\n  const contentId = generateContentId(content);\n  const checksum = crypto.createHash('sha256').update(content).digest('hex');\n  const fileName = options.name || `${contentId}.cfp.json`;\n\n  // Validate filename to prevent path traversal\n  if (!/^[a-zA-Z0-9._\\-]+$/.test(fileName) || fileName.includes('..')) {\n    throw new Error(`Invalid filename: ${fileName}`);\n  }\n\n  const objectPath = config.prefix ? `${config.prefix}/${fileName}` : fileName;\n\n  // S-1: Validate bucket name and object path to prevent command injection\n  if (!isValidBucketName(config.bucket)) {\n    throw new Error(`Invalid GCS bucket name: ${config.bucket}`);\n  }\n  if (!isValidObjectPath(objectPath)) {\n    throw new Error(`Invalid GCS object path: ${objectPath}`);\n  }\n\n  console.log(`[GCS] Uploading to gs://${config.bucket}/${objectPath}...`);\n\n  // Write content to temp file\n  const tempDir = process.env.TMPDIR || '/tmp';\n  const tempFile = path.join(tempDir, `claude-flow-upload-${Date.now()}.json`);\n  fs.writeFileSync(tempFile, content);\n\n  try {\n    // Build gcloud args (array form prevents shell injection)\n    const uploadArgs = ['storage', 'cp', tempFile, `gs://${config.bucket}/${objectPath}`];\n    if (config.projectId) uploadArgs.push(`--project=${config.projectId}`);\n    uploadArgs.push(`--content-type=${options.contentType || 'application/json'}`);\n\n    execFileSync('gcloud', uploadArgs, { encoding: 'utf-8', stdio: 'pipe' });\n\n    // Set metadata if provided","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/transfer/storage/gcs.ts#L115-L151","documentation":"After the filename check, uploadToGCS composes objectPath = config.prefix ? `${prefix}/${fileName}` : fileName and validates the whole path through isValidObjectPath() — the second half of the S-1 command-injection guard, since the path becomes a gcloud argument. A prefix containing spaces, shell metacharacters, absolute-path markers, or traversal sequences makes the combined path fail even when the filename itself is clean.","triggerScenarios":"GCSConfig.prefix values like 'my patterns/', '/abs/path', 'a;rm -rf', '../escape', or prefixes with quotes/backticks; a clean fileName combined with a prefix containing spaces or unicode; empty-but-whitespace prefixes.","commonSituations":"User-defined prefixes from config files or CLI flags; prefixes mirroring local directory trees with spaces; injection attempts on shared systems; trailing slashes doubling up ('prefix//' plus filename).","solutions":["Keep prefix segments simple: lowercase/digits/hyphens/underscores, no leading slash, no spaces or shell metacharacters — e.g. 'patterns/2024'","Sanitize user-supplied prefixes before passing GCSConfig (strip leading '/', collapse '//', reject metacharacters)","Drop the prefix entirely (flat layout) if you do not need folder structure","Treat any metacharacter in this value as hostile input — the guard exists because the path reaches a shell-launched gcloud command"],"exampleFix":"// before\nawait uploadToGCS(content, { config: { bucket: 'my-bucket', prefix: 'my patterns/2024' } });\n// space in prefix -> Invalid GCS object path: my patterns/2024/pattern.json\n\n// after\nawait uploadToGCS(content, { config: { bucket: 'my-bucket', prefix: 'patterns/2024' } });","handlingStrategy":"validation","validationCode":"function sanitizeGcsPrefix(prefix: string): string {\n  const cleaned = prefix.replace(/\\/+/g, '/').replace(/^\\/+/, '').replace(/\\/+$/, '');\n  if (!/^[a-zA-Z0-9._\\/-]*$/.test(cleaned) || cleaned.includes('..')) {\n    throw new Error(`Unsafe GCS prefix: ${JSON.stringify(prefix)}`);\n  }\n  return cleaned;\n}\n\nawait uploadToGCS(content, {\n  config: { bucket, prefix: sanitizeGcsPrefix(userPrefix) },\n});","typeGuard":"function isValidGcsObjectPath(objectPath: string): boolean {\n  return /^[a-zA-Z0-9._\\/-]+$/.test(objectPath)\n    && !objectPath.includes('..')\n    && !objectPath.startsWith('/')\n    && !/[;&|$`\"'\\s]/.test(objectPath);\n}","tryCatchPattern":null,"preventionTips":["Restrict prefixes to plain path segments: alphanumerics, hyphens, underscores, single slashes — no spaces or shell metacharacters","Treat prefix and name as untrusted input; sanitize both before building GCSConfig","Remember why the guard exists: the object path is interpolated into a gcloud CLI argument, so metacharacters are an injection vector, not just a formatting nuisance"],"tags":["gcs","object-path","validation","path-traversal","command-injection","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-14T00:17:10.932Z"}