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

  1. Remove '..' segments from the directory/root option — use a path relative to the intended base, or a clean absolute path without traversal
  2. Strip NUL bytes and backslashes from any user-supplied path before storing it in the destination config
  3. If you need a different location on the remote, configure the server-side root rather than traversing with '..'
  4. 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

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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/468538e0741ccfb2. Report an issue: GitHub.