{"record":{"id":"ccba98bf9102aa7c","repo":"can1357/oh-my-pi","slug":"upload-filename-is-invalid","errorCode":null,"errorMessage":"Upload filename is invalid","messagePattern":"Upload filename is invalid","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/blob-broker/uploaders-self-hosted.ts","lineNumber":107,"sourceCode":"\treturn value.trim();\n}\n\nfunction pathParts(value: string | undefined): string[] {\n\tif (!value) return [];\n\tconst parts = value.replaceAll(\"\\\\\", \"/\").split(\"/\");\n\tconst result: string[] = [];\n\tfor (const part of parts) {\n\t\tif (!part || part === \".\") continue;\n\t\tif (part === \"..\" || part.includes(\"\\0\"))\n\t\t\tthrow new Error(\"Destination paths cannot contain parent traversal or NUL bytes\");\n\t\tresult.push(part);\n\t}\n\treturn result;\n}\n\nfunction safeFileName(request: BlobUploadRequest): string {\n\tconst name = fileNameFor(request);\n\tif (name.includes(\"\\0\") || name === \".\" || name === \"..\") throw new Error(\"Upload filename is invalid\");\n\treturn name;\n}\n\nfunction remotePath(directory: string | undefined, filename: string): string {\n\tconst absolute = directory?.replaceAll(\"\\\\\", \"/\").startsWith(\"/\") ?? false;\n\tconst joined = [...pathParts(directory), filename].join(\"/\");\n\treturn absolute ? `/${joined}` : joined;\n}\n\nfunction encodedPath(parts: readonly string[]): string {\n\treturn parts.map(part => encodeURIComponent(part)).join(\"/\");\n}\n\nfunction endpoint(base: string, ...parts: string[]): string {\n\tconst url = new URL(base);\n\turl.pathname = `${url.pathname.replace(/\\/+$/, \"\")}/${encodedPath(parts)}`;\n\turl.search = \"\";\n\turl.hash = \"\";","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/blob-broker/uploaders-self-hosted.ts#L89-L125","documentation":"Thrown by safeFileName when the derived upload filename contains a NUL byte or is exactly '.' or '..'. fileNameFor(request) computes the name from the upload request; the library refuses names that are path metacharacters or would corrupt remote filesystem entries.","triggerScenarios":"Uploading a blob whose request-derived filename is '.', '..', or contains '\\0' — e.g. a request with an empty/weird source path that degenerates to '.', or programmatic callers passing a filename with an embedded NUL.","commonSituations":"Filename extracted from a URL/CFI/path that after normalization collapses to '.', uploading entries read from an archive with malicious names ('..' entries, NUL-padded names), or passing raw bytes-terminated C strings as filenames.","solutions":["Sanitize the filename before the upload: strip NUL bytes and reject/basename '.' and '..' values","Check what fileNameFor derives from in your request — supply an explicit valid filename instead of relying on derivation","If iterating archive/zip entries, skip or rename entries whose names are '.' or '..' or contain '\\0'","Wrap the upload in a try-catch and surface a clearer user-facing 'invalid file name' message"],"exampleFix":"// before\nawait uploadBlob({ name: \"..\", content });\n// after\nconst safe = rawName.replaceAll(\"\\0\", \"\") || \"upload.bin\";\nawait uploadBlob({ name: safe === \".\" || safe === \"..\" ? \"upload.bin\" : safe, content });","handlingStrategy":"validation","validationCode":"function sanitizeUploadName(raw: string): string {\n  const name = raw.replaceAll(\"\\0\", \"\");\n  if (!name || name === \".\" || name === \"..\") return \"upload.bin\";\n  return name;\n}\nawait uploader.upload({ ...req, name: sanitizeUploadName(req.name) });","typeGuard":"function isValidUploadName(name: string): boolean {\n  return !name.includes(\"\\0\") && name !== \".\" && name !== \"..\";\n}","tryCatchPattern":"try {\n  await uploader.upload(blob);\n} catch (err) {\n  if ((err as Error).message === \"Upload filename is invalid\") {\n    throw new Error(`Refusing upload: derived filename ${JSON.stringify(blob.name)} is '.', '..' or contains NUL`);\n  }\n  throw err;\n}","preventionTips":["Sanitize filenames derived from URLs, archives, or user input before uploading","Skip or rename '.'/'..'/NUL-containing entries when iterating archive contents","Supply an explicit filename in the upload request instead of relying on path derivation"],"tags":["filename","validation","security","upload"],"backgroundTag":"invalid-filename","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}