← Blog · MCP security · May 16, 2026

Filesystem path-boundary checklist

MCP filesystem tools need path proof before they need broader repo access.

A model-supplied path is an authorization input. If an MCP server can read, list, summarize, patch, or write files, the production question is not whether the schema accepts a string. It is whether the runtime can prove the final path stayed inside the intended workspace before host state reaches the agent.

Fast answer

  • A filesystem MCP tool is not harmless because it is local or read-only. It is authority over host state, repo state, secret-bearing paths, and sometimes customer data.
  • The boundary has to be proven before any read, write, diff, patch, summary, or upload runs: resolve cwd, normalize the requested path, canonicalize through symlinks, compare against the allowed root, and deny neighboring paths with typed receipts.
  • Scanner findings and schema lint are useful tripwires. Production proof is a paired fixture: one allowed file operation and one denied sibling, parent traversal, hidden config, symlink escape, or host-mount target through the same endpoint and trace path.
  • If the receipt cannot show requested path, canonical path, allowlist decision, symlink policy, redaction rule, caller, workspace, and operation class, the route is not ready for repeat agent use.

The production checklist

Operation class gate

Separate read, list, search, summarize, diff, patch, write, delete, execute, and upload. A route approved for read does not inherit write, patch, or command authority.

cwd and workspace anchor

Record the runtime cwd, workspace id, repo id, branch/ref if applicable, and the intended allowed root before interpreting any model-supplied path.

Canonical path proof

Normalize the requested path, resolve relative segments, follow or reject symlinks according to policy, and compare the final canonical path to the allowed prefix.

Denied-neighbor fixtures

Test parent traversal, sibling workspaces, hidden config, lockfiles, credentials, host mounts, generated artifacts, and write targets outside policy under the same caller and endpoint.

Output redaction and shape

Bound file size, match allowlisted extensions or globs, redact secrets/topology/customer data, and return typed artifacts or summaries instead of dumping unbounded content into context.

Typed denial receipt

Return a policy denial that includes requested path, canonical path or resolution failure, operation class, rule id, caller/workspace, and recovery hint.

Denied neighbors

Pair every allowed file with the path class that must fail closed.

Parent traversal

Examples: ../, ..%2f, nested symlink to parent, absolute path fallback

Expected: Deny before read/write; receipt names normalized path, canonical path decision, and allowed-root rule.

Sibling workspace or repo

Examples: ../other-customer, ../repo-b, /Volumes/shared/adjacent-project

Expected: Deny unless a separate route card explicitly names that workspace and caller. Same agent identity is not enough.

Hidden config and credentials

Examples: .env, .npmrc, .aws/credentials, SSH keys, token caches, local browser/session files

Expected: Deny or redact by default; receipt shows the secret-bearing class protected and the allowed recovery path.

Host mount or system path

Examples: /etc, /proc, /var/run/docker.sock, host-mounted volumes, CI workspace parents

Expected: Deny as host-state authority unless a reviewed admin route exists with expiration, receipt, and blast-radius owner.

Trace evidence

The receipt has to prove which host state stayed unreachable.

Filesystem containment is only operator-grade if the decision is reconstructable. Store enough evidence to show the path was normalized, resolved, classified, and blocked or allowed before content, secrets, or write authority reached the agent.

caller / tenant / workspace
tool route and operation class
runtime cwd and allowed root
requested path and raw input
normalized path
canonical path or resolution error
symlink and mount decision
matched allowlist / deny rule
file size and extension / glob class
redaction policy applied
credential lane or host resource protected
policy decision and denial code
receipt id and recovery hint

Route card

Repo-wide access is a different route, not an escalation after failure.

Some agents legitimately need broader repository context. That does not make every path in the workspace fair game. Give each filesystem lane its own caller, operation class, allowed root, redaction rule, denied neighbors, and expiration.

Filesystem route:
Caller / workspace allowed:
Allowed root / repo / branch:
Allowed operation class:
Allowed glob / extension / size:
Symlink and mount policy:
Redaction rule:
Forbidden neighboring paths:
Credential / host resource protected:
Receipt fields:
Expiration / re-review date:

Common misreads

Where filesystem safety usually collapses.

Calling a file read safe because the tool cannot write, while it can still expose secrets, private repos, host topology, customer data, or prompts.
Validating the path string but not the canonical path after cwd, symlinks, mount points, case behavior, and relative segments resolve.
Allowing repo access as a blanket instead of separating source files, generated artifacts, hidden config, lockfiles, scripts, and credential stores.
Letting a denied read retry through search, glob, summarize, archive, or upload helpers that do not share the same filesystem policy.
Logging only a generic file-not-found or permission error instead of a typed policy receipt that proves the unsafe neighbor was blocked.
Treating scanner badges as proof instead of keeping allowed and denied runtime fixtures in the promotion gate.

Related operator guides