stablyai/orca · error · Error
Unsafe computer screenshot temp path: ${outputDir}
Error message
Unsafe computer screenshot temp path: ${outputDir} What it means
Thrown by computerScreenshotTempDir() after creating the screenshot temp dir: if the resolved path is not a directory or is a symbolic link, the path is considered unsafe for writing screenshots. This guards against symlink-traversal and non-directory inode attacks on a path the agent writes screenshot data into, since the directory is created with mode 0700 but an attacker could have pre-placed a symlink or file.
Source
Thrown at src/cli/computer-format.ts:110
} as RuntimeRpcSuccess<TResult>
} catch {
// Why: temp-file export is an ergonomics optimization; keep inline screenshot
// data when disk, permissions, or path validation would otherwise fail --json.
return response
}
}
const COMPUTER_SCREENSHOT_TTL_MS = 24 * 60 * 60 * 1000
const COMPUTER_SCREENSHOT_CLEANUP_INTERVAL_MS = 60 * 60 * 1000
const COMPUTER_SCREENSHOT_CLEANUP_MARKER = '.last-cleanup'
function computerScreenshotTempDir(): string {
const outputDir =
process.env.ORCA_COMPUTER_SCREENSHOT_TMPDIR || join(tmpdir(), 'orca-computer-use')
mkdirSync(outputDir, { recursive: true, mode: 0o700 })
const stat = lstatSync(outputDir)
if (!stat.isDirectory() || stat.isSymbolicLink()) {
throw new Error(`Unsafe computer screenshot temp path: ${outputDir}`)
}
if (typeof process.getuid === 'function' && stat.uid !== process.getuid()) {
throw new Error(`Computer screenshot temp path is not owned by the current user: ${outputDir}`)
}
chmodSync(outputDir, 0o700)
return outputDir
}
function cleanupComputerScreenshots(outputDir: string): void {
const now = Date.now()
const markerPath = join(outputDir, COMPUTER_SCREENSHOT_CLEANUP_MARKER)
try {
// Why: agents can call computer-use CLI commands in loops; a marker keeps
// temp cleanup from becoming a synchronous directory scan per screenshot.
if (statSync(markerPath).mtimeMs > now - COMPUTER_SCREENSHOT_CLEANUP_INTERVAL_MS) {
return
}
} catch {View on GitHub (pinned to 1136503c6a)
Solutions
- Point ORCA_COMPUTER_SCREENSHOT_TMPDIR at a real directory you own, or unset it to use the default.
- Remove the offending non-directory/symlink entry at the resolved path so mkdirSync can recreate it as a directory.
- Avoid symlinks in the screenshot temp path; resolve them before setting the env var.
Example fix
# before export ORCA_COMPUTER_SCREENSHOT_TMPDIR=/tmp/my-link # symlink # after export ORCA_COMPUTER_SCREENSHOT_TMPDIR=/tmp/real-dir # mkdir -p first
Defensive patterns
Strategy: validation
Validate before calling
import { lstatSync } from 'node:fs'
function safeScreenshotTmpdir(p: string): string {
const st = lstatSync(p)
if (!st.isDirectory() || st.isSymbolicLink()) {
throw new Error(`Refusing unsafe screenshot tmpdir: ${p}`)
}
return p
} Type guard
function isRealDirectory(p: string): boolean {
try {
const st = lstatSync(p)
return st.isDirectory() && !st.isSymbolicLink()
} catch {
return false
}
} Prevention
- Never set ORCA_COMPUTER_SCREENSHOT_TMPDIR to a symlink.
- Pre-create the directory owned by the runtime user before launch.
- Keep the temp dir out of world-writable shared paths prone to tampering.
When it happens
Trigger: ORCA_COMPUTER_SCREENSHOT_TMPDIR (or the default <tmpdir>/orca-computer-use) resolves to a regular file, a device, or a symlink rather than a real directory owned by the process.
Common situations: Setting ORCA_COMPUTER_SCREENSHOT_TMPDIR to an existing file or a symlink, a shared /tmp where another user or a broken cleanup script left a file at that name, or pointing the env var at a path inside a symlinked mount.
Related errors
- Computer screenshot temp path is not owned by the current us
- Clone path must be inside the destination directory
- Access denied: submodule path escapes the selected worktree
- Path "${filePath}" resolves outside the worktree
- File changed during upload staging: '${displayPath}'
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/77ce9dd5f38946f0.
Report an issue: GitHub.