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
- Validate identifiers with the worker-name/task-id regexes before calling team state APIs
- Reject any input containing '/', '\\', '..' or leading dots before constructing paths
- 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
- Never build filesystem paths from raw user/network input
- Whitelist identifiers against strict regexes before any state API call
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
- invalid state key
- scale_down_cleanup_debt_path_escape:${path}
- [ask] invalid --agent-prompt role "${role}". Expected lowerc
- invalid detached leader parent environment
- run directory escapes the authorized runs root
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/4acc6978e26f20d1.
Report an issue: GitHub.