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

fileName must not contain ".."

Error message

fileName must not contain ".."

What it means

Thrown when the trimmed fileName contains "..". Filenames are joined into state directory paths, so double dots could traverse out of the state directory — they are explicitly rejected before the pattern check.

Source

Thrown at src/mcp/state-paths.ts:163

    throw new Error('mode must match ^[A-Za-z0-9_-]{1,64}$');
  }
  return normalized;
}

export function getStateFilename(mode: string): string {
  return `${validateStateModeSegment(mode)}${STATE_FILE_SUFFIX}`;
}

export function validateStateFileName(fileName: unknown): string {
  if (typeof fileName !== 'string') {
    throw new Error('fileName must be a string');
  }
  const normalized = fileName.trim();
  if (!normalized) {
    throw new Error('fileName must be a non-empty string');
  }
  if (normalized.includes('..')) {
    throw new Error('fileName must not contain ".."');
  }
  if (normalized.includes('/') || normalized.includes('\\')) {
    throw new Error('fileName must not contain path separators');
  }
  if (!STATE_FILE_NAME_PATTERN.test(normalized)) {
    throw new Error('fileName must match ^[A-Za-z0-9._-]{1,128}$');
  }
  return normalized;
}

function convertWindowsToWslPath(raw: string): string {
  const m = /^([a-zA-Z]):[\\/](.*)$/.exec(raw);
  if (!m) return raw;
  const drive = m[1].toLowerCase();
  const rest = String(m[2] || '').replace(/\\/g, '/');
  const mountRoot = `/mnt/${drive}`;
  if (!existsSync(mountRoot)) return raw;
  return rest ? `${mountRoot}/${rest}` : mountRoot;

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Remove '..' sequences from generated filenames
  2. Use only the pattern-legal set: letters, digits, dot, underscore, hyphen (single dots are fine, e.g. "state.json")
  3. Sanitize untrusted names: name.replace(/\.\./g, "")

Example fix

// before
getStateFilePath("../secret.json");
// after
getStateFilePath("secret.json");
Defensive patterns

Strategy: validation

Validate before calling

fileName = fileName.replace(/\.\./g, '');

Type guard

function hasNoDotDot(v: string): boolean { return !v.includes('..'); }

Prevention

When it happens

Trigger: fileName: "..json", fileName: "a..b.json", or fileName: ".." attempting traversal.

Common situations: Attempting to point at files outside the state directory; double-dot typos in generated names; adversarial input probing path handling.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


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