paperclipai/paperclip · error

post-upload command cwd escapes the operation's target root

Error message

post-upload command cwd escapes the operation's target root: ${raw}

What it means

Confinement guard (Security Condition C2): the post-upload command `cwd`, while absolute and traversal-free, does not lie within any of the operation's own file-mapping target paths, so it would run outside the synced root and is rejected before handoff.

Solutions

  1. Set the post-upload command cwd to a path inside the operation's target root.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at packages/adapter-utils/src/command-managed-runtime.ts:194 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-08-18). Data as JSON: /api/errors/3ca28f2688881cd7. Report an issue: GitHub.

Appendix: source

Thrown at packages/adapter-utils/src/command-managed-runtime.ts:245

 * provider ever sees it. `cwd` (when present) MUST be an absolute POSIX path with
 * no `..` segment, confined to (equal to or under) one of the operation's own
 * file-mapping target paths. Commands with no `cwd` are unconstrained here and
 * default to the runtime's stable command cwd at exec time.
 */
export function assertPostUploadCommandsConfined(operations: readonly SandboxSyncOperation[]): void {
  for (const operation of operations) {
    const commands = operation.postUploadCommands ?? [];
    if (commands.length === 0) continue;
    const targetRoots = operation.files.map((mapping) => path.posix.normalize(mapping.targetPath));
    for (const command of commands) {
      if (command.cwd == null) continue;
      const raw = command.cwd;
      if (!path.posix.isAbsolute(raw) || raw.split("/").includes("..")) {
        throw new Error(`post-upload command cwd is not a confined absolute POSIX path: ${raw}`);
      }
      const normalized = path.posix.normalize(raw);
      const within = targetRoots.some(
        (root) => normalized === root || normalized.startsWith(`${root}/`),
      );
      if (!within) {
        throw new Error(`post-upload command cwd escapes the operation's target root: ${raw}`);
      }
    }
  }
}

export function createCommandManagedRuntimeClient(input: {
  runner: CommandManagedRuntimeRunner;
  commandCwd: string;
  timeoutMs: number;
  shellCommand?: "bash" | "sh" | null;
}): SandboxManagedRuntimeClient {
  const shellCommand = preferredShellForSandbox(input.shellCommand);
  const runShell = async (
    script: string,
    opts: {

View on GitHub (pinned to 3f1d897a7c)