can1357/oh-my-pi · error · Error
Destination paths cannot contain parent traversal or NUL byt
Error message
Destination paths cannot contain parent traversal or NUL bytes
What it means
Thrown by pathParts when a configured destination directory path (or its segments) contains a '..' parent-traversal segment or a NUL byte. The library normalizes backslashes/slashes but refuses to build remote paths that could escape the intended root or break remote filesystems.
Source
Thrown at packages/coding-agent/src/blob-broker/uploaders-self-hosted.ts:99
return { id, uploadToken, ...(downloadBase ? { downloadBase } : {}) };
}
function requiredStringOption(config: DestinationRuntimeConfig, key: string): string {
const value = requireOption(config, key);
if (typeof value !== "string" || value.trim() === "") {
throw new Error(`Destination option ${key} must be a non-empty string`);
}
return value.trim();
}
function pathParts(value: string | undefined): string[] {
if (!value) return [];
const parts = value.replaceAll("\\", "/").split("/");
const result: string[] = [];
for (const part of parts) {
if (!part || part === ".") continue;
if (part === ".." || part.includes("\0"))
throw new Error("Destination paths cannot contain parent traversal or NUL bytes");
result.push(part);
}
return result;
}
function safeFileName(request: BlobUploadRequest): string {
const name = fileNameFor(request);
if (name.includes("\0") || name === "." || name === "..") throw new Error("Upload filename is invalid");
return name;
}
function remotePath(directory: string | undefined, filename: string): string {
const absolute = directory?.replaceAll("\\", "/").startsWith("/") ?? false;
const joined = [...pathParts(directory), filename].join("/");
return absolute ? `/${joined}` : joined;
}
function encodedPath(parts: readonly string[]): string {View on GitHub (pinned to 9690622007)
Solutions
- Remove '..' segments from the directory/root option — use a path relative to the intended base, or a clean absolute path without traversal
- Strip NUL bytes and backslashes from any user-supplied path before storing it in the destination config
- If you need a different location on the remote, configure the server-side root rather than traversing with '..'
- Pre-sanitize with the same rule the library uses: split on /, drop '' and '.', reject '..' and '\0'
Example fix
// before
{ "root": "/var/www/../sensitive" }
// after
{ "root": "/srv/uploads" } // point directly at the intended directory, no '..' segments Defensive patterns
Strategy: validation
Validate before calling
function assertSafeRemotePath(dir: string | undefined): void {
if (!dir) return;
for (const part of dir.replaceAll("\\", "/").split("/")) {
if (part === ".." || part.includes("\0")) throw new Error(`unsafe destination path: ${JSON.stringify(dir)}`);
}
}
assertSafeRemotePath(destConfig.root);
assertSafeRemotePath(destConfig.directory); Type guard
function isSafePathPart(part: string): boolean {
return part !== ".." && !part.includes("\0");
} Try / catch
try {
await uploader.upload(blob);
} catch (err) {
if ((err as Error).message.includes("parent traversal or NUL")) {
throw new Error("Destination directory contains '..' or NUL — configure a clean path under the intended root");
}
throw err;
} Prevention
- Never accept '..' segments in user-supplied destination paths
- Strip NUL bytes and normalize backslashes from any path built from external input
- Reconfigure the server-side root instead of traversing upward with '..'
- Reuse the library's normalization rules (split on '/', drop '' and '.') in your own config validation
When it happens
Trigger: Setting a destination option like root/publicBase/directory (used via joined, relative, ftpUploadUrl, target, parts, directoryParts) to something like '../../etc/webroot', 'a\0b', or a path that after backslash-to-slash normalization contains '..'.
Common situations: Trying to write outside the configured web root by using relative parent paths, a directory value built from unsanitized user input containing NUL, or Windows-style relative paths like '..\uploads'.
Related errors
- Shared-folder destination escapes its configured root
- Absolute paths are not allowed in ${scheme}:// URLs: ${rawPa
- Path traversal (..) is not allowed in ${scheme}:// URLs: ${r
- Unsafe #{scheme}:// path (absolute or traversal): #{path}
- Invalid path: ${localPath} resolves outside working director
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/468538e0741ccfb2.
Report an issue: GitHub.