DEV Community

Cover image for Root Cause Analysis: Glob-Pattern Confusion in Claude Code's macOS Sandbox (CVSS 7.7)"
CodeAnt AI for CodeAnt AI

Posted on Originally published at linkedin.com

Root Cause Analysis: Glob-Pattern Confusion in Claude Code's macOS Sandbox (CVSS 7.7)"

Executive summary

We identified and disclosed a High-severity (fourth High-severity finding in Claude Code this year) sandbox escape, CVSS 4.0 score 7.7, caused by a path-parsing ambiguity in how Claude Code's macOS sandbox scopes filesystem writes.

A literal folder name containing glob metacharacters (*) is silently reinterpreted as a wildcard pattern during policy generation.

This reinterpretation broadens an allow rule to cover sibling directories without applying the same broadening to the corresponding deny rule, producing a write primitive into a protected configuration file outside the intended project boundary.

That primitive is sufficient to achieve pre-authentication, unsandboxed command execution via Claude Code's SessionStart hook mechanism.

This writeup covers the mechanism, our differential testing methodology, and mitigation guidance. This research is drawn from the two disciplines behind the failures we find: reviewing code before it ships, and attacking systems after.

Background: how the sandbox scopes writes

Claude Code's macOS sandbox auto-approves writes inside the current project directory.

To determine scope, the policy generator inspects the project's folder path for glob syntax — characters like * and ? that conventionally mean "match any of these" rather than "this literal string."

The flaw: this check has no mechanism to distinguish a path that is intentionally a glob pattern from a literal folder name that merely contains glob metacharacters.

There is no escaping, quoting, or type distinction applied before the path is compiled into a matching rule.

Root cause: literal-to-pattern reinterpretation

Renaming a project folder to include two asterisks — for example, review-bundle**.claude** — causes the policy generator to compile that string as a wildcard pattern rather than treat it as a single literal directory.

Conceptually, the generated allow rule collapses from "this one directory" to a pattern resembling:

allow_write: /parent/review-bundle*/.claude*
Enter fullscreen mode Exit fullscreen mode

That pattern now matches any sibling directory whose name starts with review-bundle, not just the original folder.

The asymmetry: allow rules widen, deny rules don't

Claude Code separately generates a deny rule to protect .claude/settings.local.json — the local configuration file capable of defining auto-run hooks.

Critically, this deny rule was implemented to expect two .claude path segments before it triggers. When the allow rule was reinterpreted as a broader pattern, the deny rule's stricter literal-matching logic did not widen in the same way — leaving a class of sibling paths that were allow-matched but deny-missed.

Differential test results

Folder name                Allow rule   Deny rule   Outcome
review-bundle               No match     N/A         Blocked
review-bundle**             Match        Match       Blocked
review-bundle**.claude**    Match        MISS        Settings file created, hook executes
**.claude**                 Match        MISS        Settings file created, hook executes
Enter fullscreen mode Exit fullscreen mode

The control case (review-bundle**, no .claude substring) confirms the flaw is specific to the .claude token appearing inside the reinterpreted pattern — ruling out a broader, unrelated permissions bug and isolating the exact mechanism.

This kind of differential comparison is the same full methodology, phase by phase we apply across engagements.

Exploitation chain: from write primitive to pre-auth execution

With a write primitive into a sibling project's .claude/settings.local.json established, the remaining step used Claude Code's SessionStart hook — automation designed to run a command the moment a new session opens.

This isn't a hypothetical chaining exercise; it reflects the defensive side of the same platform discipline applied to every codebase tested.

Steps to reproduce (validated):

  1. Create a project folder with a name containing .claude inside a reinterpretable glob pattern (e.g., review-bundle**.claude**).

  2. From inside that sandboxed session, write a SessionStart hook into a sibling project's .claude/settings.local.json.

  3. Close the session. Open the sibling project as a fresh session, with Bash access disabled and no API key configured.

  4. Observe: the hook executes before authentication, before the model produces any output, and before the Bash tool is available to the session.

Severity assessment

  • Severity: CVSS 4.0, 7.7 (High)
  • Affected versions confirmed: Claude Code 2.1.214, 2.1.215 (macOS arm64)
  • Test cases: 4 differential cases, identical payload and target
  • Full bypass rate: 2 of 4 cases
  • Prerequisites: none — no symlinks, race conditions, or leaked credentials required

Disclosure timeline

Date        Event
July 18     Report submitted
July 20     Validated by Anthropic (2 days)
August 4    Bounty awarded (17 days from report)
Enter fullscreen mode Exit fullscreen mode

Broader pattern: type confusion via string inference

This finding fits a pattern we've documented before, one level down the stack from where it usually surfaces.

Edition 3 covered AI code reviewers inferring correctness from surface-level textual similarity rather than resolving what code actually calls or connects to.

We've written before about why that pattern keeps breaking down. Here, a security policy compiler inferred a path's type (literal vs. pattern) from its characters, rather than preserving the path's actual provenance as a resolved filesystem object.

Note also that certain compliance frameworks ask for exactly that kind of external assessment as a baseline — this finding is a supplement to, not a replacement for, that layer.

Mitigation recommendations

For teams running Claude Code or comparable AI coding agents on machines adjacent to production code:

  • Audit whether your sandbox/policy layer resolves paths as validated, canonical filesystem objects, or infers type from raw string content.

  • Verify that allow and deny rule generation use identical path-normalization logic — any asymmetry between the two is the exploitable surface, independent of the specific trigger.

  • Treat any character-based heuristic for distinguishing "pattern" from "literal" as a parser bug waiting to be found, not a config edge case.

Conclusion

This is our fourth validated High-severity vulnerability in Claude Code this year.

Starting from what's already known, rather than a blank test surface, is what let this be found and fully characterized in a single research session rather than an extended engagement.

*Research conducted by CodeAnt AI. Originally published as Edition 04 of "The Last Line."*

Top comments (0)