schollz/croc · error · Error
Remote path escapes the destination: ${value}
Error message
Remote path escapes the destination: ${value} What it means
cleanSegments() splits a remote path on '/' (after converting backslashes) and throws if any segment is '..'. This blocks path-traversal: a peer-supplied path like '../../etc/passwd' must never escape the destination directory chosen by the receiver.
Source
Thrown at web/src/protocol/metadata.ts:15
import { base64ToBytes } from "./bytes";
import type {
OfferedFile,
SenderInfoWire,
TransferOffer,
WireFileInfo,
} from "./types";
function cleanSegments(value: string) {
const replaced = value.replaceAll("\\", "/");
if (replaced.includes("\0")) throw new Error("A remote path contains a null byte");
const segments: string[] = [];
for (const segment of replaced.split("/")) {
if (segment === "" || segment === ".") continue;
if (segment === "..") throw new Error(`Remote path escapes the destination: ${value}`);
if ([...segment].some((character) => !/\P{C}/u.test(character))) {
throw new Error(`Remote path contains a non-printable character: ${value}`);
}
segments.push(segment);
}
return segments;
}
export function normalizeFolder(value = ".") {
if (/^(?:[a-zA-Z]:|\/)/.test(value)) {
throw new Error(`Remote path must be relative: ${value}`);
}
const segments = cleanSegments(value);
const normalized = segments.join("/") || ".";
if (normalized.includes(".ssh")) {
throw new Error(`Remote path is not allowed: ${value}`);
}
return normalized;View on GitHub (pinned to e25f1bdc04)
Solutions
- Refuse the transfer from the peer that sent the traversal payload; this is a security guard, not a recoverable condition.
- If you are sending, normalize folders to clean relative paths ('a/b', not 'a/../b') before constructing SenderInfoWire.
- In security tests, assert this exact error is thrown for traversal payloads — its absence is a vulnerability.
Defensive patterns
Strategy: validation
Validate before calling
function isSafeRelativePath(value: string): boolean {
const segs = value.replaceAll("\\", "/").split("/");
return !segs.includes("..");
}
// check before accepting an offer
if ([...(info.FilesToTransfer ?? []), ...(info.EmptyFoldersToTransfer ?? [])]
.some((f) => !isSafeRelativePath(f.fr ?? "."))) {
rejectOffer("traversal attempt");
} Try / catch
try {
const offer = validateSenderInfo(info);
} catch (error) {
if (error instanceof Error && error.message.startsWith("Remote path escapes the destination")) {
abortTransferAndWarnUser("peer attempted path traversal");
return;
}
throw error;
} Prevention
- Never relax or catch-and-continue past this guard; escaping paths must abort the transfer.
- On the sender, canonicalize folders before offering so '..' segments never reach the wire.
- Compose destination paths only via the validated {folder, name} pair, never raw peer strings.
When it happens
Trigger: validateSenderInfo() processes an offer whose file folder/name or empty-folder entry contains a '..' segment after backslash normalization — e.g. fr='docs/../..' or n='a/../../x'.
Common situations: Hostile sender attempting directory traversal against the receiver's download directory; fuzz corpus containing traversal payloads; legitimate sender whose folder strings were built with '..' segments that were never normalized on the Go side (rare — croc normalizes before sending).
Related errors
- A remote path contains a null byte
- Remote path contains a non-printable character: ${value}
- Remote path must be relative: ${value}
- Remote path is not allowed: ${value}
- Remote filename must be a basename: ${nameValue}
AI-assisted analysis of schollz/croc@e25f1bdc04 (2026-08-15).
Data as JSON: /api/errors/00c5ac3f3a4cad1c.
Report an issue: GitHub.