Yeachan-Heo/oh-my-codex · critical · Error

Path traversal detected: path is outside the allowed directo

Error message

Path traversal detected: path is outside the allowed directory

What it means

Generic path-traversal guard in team state helpers: a resolved file path is neither equal to nor prefixed by the allowed root directory. Thrown by assertPathWithinDir, used when building mailbox, claim-lock, approval, and task file paths.

Source

Thrown at src/team/state.ts:494

// injection verification; keep the default ack budget above that steady-state
// control-plane cadence to avoid spurious fallback/failed confirmations.
const DEFAULT_DISPATCH_ACK_TIMEOUT_MS = 2_000;
const MIN_DISPATCH_ACK_TIMEOUT_MS = 100;
const MAX_DISPATCH_ACK_TIMEOUT_MS = 10_000;

function isTerminalTaskStatus(status: TeamTaskStatus): boolean {
  return isTerminalTeamTaskStatus(status);
}

function canTransitionTaskStatus(from: TeamTaskStatus, to: TeamTaskStatus): boolean {
  return canTransitionTeamTaskStatus(from, to);
}

function assertPathWithinDir(filePath: string, rootDir: string): void {
  const normalizedRoot = resolve(rootDir);
  const normalizedPath = resolve(filePath);
  if (normalizedPath !== normalizedRoot && !normalizedPath.startsWith(normalizedRoot + sep)) {
    throw new Error('Path traversal detected: path is outside the allowed directory');
  }
}

function validateWorkerName(name: string): void {
  if (!WORKER_NAME_SAFE_PATTERN.test(name)) {
    throw new Error(
      `Invalid worker name: "${name}". Must match /^[a-z0-9][a-z0-9-]{0,63}$/ (lowercase alphanumeric + hyphens, max 64 chars).`
    );
  }
}

function validateTaskId(taskId: string): void {
  if (!TASK_ID_SAFE_PATTERN.test(taskId)) {
    throw new Error(
      `Invalid task ID: "${taskId}". Must be a positive integer (digits only, max 20 digits).`
    );
  }
}

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Validate identifiers with the worker-name/task-id regexes before calling team state APIs
  2. Reject any input containing '/', '\\', '..' or leading dots before constructing paths
  3. Use the library's own sanitize/validation helpers rather than raw user strings

Example fix

// before
const mailbox = mailboxPath(req.body.worker, teamStateRoot); // may throw traversal

// after
if (!/^[a-z0-9][a-z0-9-]{0,63}$/.test(req.body.worker)) throw new Error('bad worker name');
const mailbox = mailboxPath(req.body.worker, teamStateRoot);
Defensive patterns

Strategy: validation

Validate before calling

function safeSegment(s: string): boolean {
  return typeof s === 'string' && !s.includes('/') && !s.includes('\\\\') && !s.includes('..') && !s.startsWith('.') && s.length > 0 && s.length <= 128;
}

Try / catch

catch (e) {
  if ((e as Error).message.includes('Path traversal detected')) {
    throw new Error('rejecting unsafe identifier used to build team state path');
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling taskClaimLockDir, mailboxPath, mailboxLockDir, approvalPath, or taskFilePath with a worker name/task id/team name containing '..', '/', or absolute path components that resolve outside the state root.

Common situations: Passing unsanitized user input (worker names or task ids from CLI args or network) into team state APIs; hand-constructed identifiers containing slashes or traversal sequences.

Related errors


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/4acc6978e26f20d1. Report an issue: GitHub.