[BUG] Sandbox allowRead glob patterns silently fail when any directory contains a symlink loop

Resolved 💬 1 comment Opened May 6, 2026 by p-kabelka Closed Jun 3, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

The expandGlobPattern function uses fs.readdirSync(baseDir, { recursive: true }) which follows symlinks. If any project under the base directory contains a symlink loop (e.g., example/ -> ../ creating infinite recursion), readdirSync hits ELOOP and throws. The error is silently caught, returning an empty array, and all allowRead entries are dropped with no warning.

A single project with a symlink loop anywhere in ~/git breaks allowRead for every project.

What Should Happen?

allowRead: ["~/git/*"] should expand to the direct children of ~/git and add --ro-bind entries for each, regardless of how many files exist inside those child directories. A single * glob should only require a non-recursive directory listing of the base directory.

Error Messages/Logs

Error message from strace:

2239180 openat(32, "mock/mock/integration-tests/setup-playbook/roles/fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh/example/ansible-role-fix-root-ssh", O_RDONLY|O_DIRECTORY) = -1 ELOOP (Too many levels of symbolic links)

Steps to Reproduce

  1. Run mkdir -p ~/git/good-project
  2. Run mkdir -p ~/git/bad-project/roles/myrole/example
  3. Run cd ~/git/bad-project/roles/myrole/example
  4. Run ln -s .. ansible-role-myrole
  5. Use the following minimal ~/.claude/settings.json:
{
  "sandbox": {
    "enabled": true,
    "autoAllowBashIfSandboxed": false,
    "allowUnsandboxedCommands": false,
    "filesystem": {
      "denyRead": [
        "~/"
      ],
      "allowRead": [
        "~/git/*"
      ]
    }
  }
}
  1. Run cd ~/git/good-project and run claude
  2. Press ! to enter shell mode and run ls -la ~/git
  3. Observe that only the good-project is listed

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.131 (Claude Code)

Platform

Google Vertex AI

Operating System

Other Linux

Terminal/Shell

Other

Additional Information

_No response_

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗