Skip to content

fix(mcp): confine trace paths to allowed roots #6

Description

@pratik-saptarshi

Problem

run_fastcontext accepts a caller-controlled trajectory_path and, for relative values, joins it to repo without a containment check after normalization. In src/fastcontext_mcp/runtime.py:206-217, a path such as ../outside.jsonl can resolve outside the intended root before the subprocess is invoked.

Evidence

  • src/fastcontext_mcp/runtime.py:206-217 builds traj from user input and only does a lexical repo / traj join for relative paths.
  • The tool schema and README both describe repo_path as being constrained to allowed roots, but the current trajectory handling does not enforce the same boundary.

Impact

This is a path-safety bug with arbitrary-file-write potential within the privileges of the service account. Even if the payload is only a trace file, the runtime no longer guarantees that trace artifacts stay under the repo or allowed root.

Recommended remediation

  • Resolve the candidate path first.
  • Enforce containment after normalization with a real containment check such as resolved_path.is_relative_to(repo_root) or equivalent.
  • Reject absolute paths and traversal escapes before passing --traj to the subprocess.
  • If symlinks matter in the threat model, validate against resolved parents, not only lexical joins.

Regression tests to add

  • Reject trajectory_path="../outside.jsonl".
  • Reject normalized traversal such as subdir/../../outside.jsonl.
  • Accept an in-root relative path like traces/run.jsonl and confirm the resolved path stays under the repo root.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions