Skip to content

fix(security): use lstat in claude session discovery to skip symlinks (#153 — gap 2)#157

Open
ousamabenyounes wants to merge 1 commit intogetagentseal:mainfrom
ousamabenyounes:fix/symlink-lstat-providers
Open

fix(security): use lstat in claude session discovery to skip symlinks (#153 — gap 2)#157
ousamabenyounes wants to merge 1 commit intogetagentseal:mainfrom
ousamabenyounes:fix/symlink-lstat-providers

Conversation

@ousamabenyounes
Copy link
Copy Markdown

@ousamabenyounes ousamabenyounes commented Apr 25, 2026

Summary

Addresses gap #2 of #153 ("Walk functions (providers/claude.ts) don't check for symlinks. Use lstat, skip symbolic links.").

findDesktopProjectDirs and discoverSessions in src/providers/claude.ts walk the session tree with stat, which transparently follows symbolic links. A symlink under ~/.claude/projects/ (or anywhere within the macOS / Linux / Windows Claude Desktop sessions trees) lets the walk descend to any path the calling user can read — outside the intended sandbox.

Fix

Switch the imports from statlstat and explicitly skip symbolic links:

const s = await lstat(full).catch(() => null)
if (!s || s.isSymbolicLink() || !s.isDirectory()) continue

Regular directories behave identically; only symlinks are refused. Three call sites in claude.ts:

  • top-level walk in findDesktopProjectDirs
  • inner projects/* walk in findDesktopProjectDirs
  • ~/.claude/projects/ walk in discoverSessions

Verification

  • Baseline: 355 pass, 0 fail
  • Post-fix: 357 pass, 0 fail (+2 symlink tests, 0 regressions)
  • New tests/providers/claude-symlink.test.ts fails on the unfixed code (verified by stashing the fix and re-running — 'shady-link' was discovered)
  • npx tsc --noEmit clean
  • No bracket-assign on {}-init maps in src/parser.ts or src/providers/ (semgrep guard)

Out of scope

Gap #1 of #153 (ANSI sanitization of displayed strings) is the companion PR.

The same stat-vs-lstat pattern exists in other providers (pi, codex, copilot). Per the issue text the symptom was reported in providers/claude.ts, and a single-provider PR is easier to review than a sweep. Happy to follow up across the other providers in a separate PR if you'd like.

Files changed

File Change
src/providers/claude.ts statlstat; explicit symlink skip at 3 call sites
tests/providers/claude-symlink.test.ts new — symlink dropped, regular dir kept

Vibe Coded by Ousama Ben Younes
Developed With Ora Studio (Claude Code)

…getagentseal#153)

`findDesktopProjectDirs` and `discoverSessions` in `src/providers/claude.ts`
walked the session tree with `stat`, which transparently follows symbolic
links. A symlink inside `~/.claude/projects/` (or in the macOS / Linux /
Windows desktop sessions tree) would let the walk descend anywhere on the
filesystem the calling user can read.

Switch to `lstat` and explicitly skip symbolic links. Regular directories
behave identically; only symlinked entries are now refused.

Adds `tests/providers/claude-symlink.test.ts` covering both branches:
- a symlinked entry inside the projects dir is dropped from
  `discoverSessions` output
- a regular project directory next to it is still discovered

Addresses gap getagentseal#2 from getagentseal#153 ("Walk functions (providers/claude.ts) don't
check for symlinks. Use lstat, skip symbolic links."). Gap getagentseal#1 (ANSI
sanitization) is in a separate PR.

Co-Authored-By: Ora Studio <noreply@oratelecom.net>
@Qodo-Free-For-OSS
Copy link
Copy Markdown

Hi, The new symlink test creates a directory symlink without Windows-safe options or error handling, which can fail on win32 (often EPERM/EACCES) and break CI/dev runs on Windows.

Severity: action required | Category: reliability

How to fix: Make symlink creation Windows-safe

Agent prompt to fix - you can give this to your LLM of choice:

Issue description

tests/providers/claude-symlink.test.ts creates a directory symlink in a way that is likely to fail on Windows.

Issue Context

On win32, fs.promises.symlink() frequently requires admin privileges and/or an explicit link type; otherwise it throws (EPERM/EACCES), making the test suite fail on Windows.

Fix Focus Areas

  • tests/providers/claude-symlink.test.ts[37-41]

Potential approaches:

  • Use await symlink(realTarget, linkPath, 'dir') on Windows/macOS/Linux.
  • Or on Windows prefer junction (symlink(target, path, 'junction')) for directory links.
  • If symlinks are not permitted in the environment, skip the test with a clear reason when symlink() fails with EPERM/EACCES.

We noticed a couple of other issues in this PR as well - happy to share if helpful.


Found by Qodo. Free code review for open-source maintainers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants