Security: index_codebase path is unbounded, allows arbitrary host file read via search_code (MCP tool)

Author: router0mailCreated Sep 13, 2026Updated Sep 13, 2026

Summary

ensureAbsolutePath() (packages/mcp/src/utils.ts:15-24) is just path.resolve() — it does no confinement/allowlist check against a project or workspace root. This lets the index_codebase MCP tool index any directory on the host filesystem (sibling repos, ~/.ssh, ~/.aws, ~/.kube, ~/.config, etc.). The customExtensions parameter also additively widens the default file-extension allowlist, so files like .pem/.key/.yaml/.json can be included even though they aren't indexed by default.

Once a directory is indexed (stored in the configured vector DB), search_code returns raw file content (up to 5000 chars) plus the file's path verbatim in the tool response. So a two-call sequence exfiltrates arbitrary host file content through normal MCP tool output:

  1. index_codebase with path pointed outside the intended project (e.g. ~/.ssh, ~/.aws, or a sibling repo the current session shouldn't have access to)
  2. search_code with a query matching known content (e.g. "BEGIN PRIVATE KEY", "aws_secret_access_key") against that same path

This is a plain local-misuse risk on its own, but it's also the classic MCP "lethal trifecta" amplifier: if an agent using this MCP server ever processes untrusted content (a webpage, an email, a file) containing a prompt injection, that injection can instruct the agent to make exactly these two tool calls — turning this into a remote data-exfiltration primitive, not just a local misconfiguration.

Prior attempt

PR #328 ("refactor: enhance path resolution safety...") touches this exact function but doesn't close the gap — it adds a denylist of 5 hardcoded prefixes (/etc, /var/private, /root, C:\Windows, C:\Users\Administrator). That's trivially bypassed: ~/.ssh, ~/.aws, ~/.kube, ~/.config, any sibling repo, /home/*, /mnt/*, etc. all sail through unaffected. It's also framed as a refactor rather than a security fix, so it may not have gotten security-conscious review.

Suggested fix

Replace the denylist approach with an allowlist/confinement check: resolve the requested path with fs.realpathSync, resolve the intended project/workspace root the same way, and reject any path that doesn't sit under that root (or under an explicit, user-configured list of allowed roots) — rather than trying to enumerate forbidden paths.

Disclosure note

No SECURITY.md exists in this repo and private vulnerability reporting isn't enabled, so filing this as a normal public issue. The vulnerable function is ~10 lines and already fully public in master, and PR #328's own diff (also public) already shows the same line and an inadequate attempt at fixing it, so nothing here goes beyond what's already derivable from the public repo.

Source: zilliztech/claude-context