clawwork-ai/ClawWork

[Bug] readContextFile crashes on Windows via /dev/fd/<fd>

Open

#381 opened on Apr 15, 2026

View on GitHub
 (2 comments) (0 reactions) (0 assignees)TypeScript (63 forks)github user discovery
area/artifacthelp wantedkind/bug

Repository metrics

Stars
 (519 stars)
PR merge metrics
 (PR metrics pending)

Description

Problem

readContextFile uses realpathSync('/dev/fd/${fd}') as a TOCTOU-safe way to resolve the real path of an opened file descriptor. This syntax is Linux/macOS only — Windows has no /dev/fd filesystem, so the call throws ENOENT and every context file read fails on Windows. build:win is a supported release target, so this breaks a shipping platform.

Location

File: packages/desktop/src/main/context/file-reader.ts:10-17

export function readContextFile(absolutePath: string, contextFolders: string[]): FileReadResult {
  const fd = openSync(absolutePath, 'r');
  try {
    const realPath = realpathSync(`/dev/fd/${fd}`);
    const allowed = contextFolders.some((folder) => {
      const realFolder = realpathSync(folder);
      return realPath.startsWith(realFolder + sep) || realPath === realFolder;
    });
    if (!allowed) throw new Error('path outside allowed context folders');

Tests don't catch this because packages/desktop/test/file-reader.test.ts:27 mocks realpathSync unconditionally, so CI stays green while Windows users hit the bug immediately.

Fix Approach

  1. Branch on process.platform:
    • On linux / darwin: keep the current /dev/fd/${fd} approach.
    • On win32: fall back to realpathSync(absolutePath) (slightly weaker TOCTOU guarantee, but the only portable option).
  2. Optionally extract the helper as resolveFdRealPath(fd, absolutePath) and unit-test both branches (without a blanket mock).

Verification

  1. Run pnpm check — must pass.
  2. Manual on Windows: add a context folder, send a message that attaches a file from it; expect the file content to be attached, not an ENOENT error.

Context

  • WG: Artifact & File System
  • Priority: Low
  • Estimated effort: 20-30 minutes

Contributor guide