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.
Problem
run_fastcontextaccepts a caller-controlledtrajectory_pathand, for relative values, joins it torepowithout a containment check after normalization. Insrc/fastcontext_mcp/runtime.py:206-217, a path such as../outside.jsonlcan resolve outside the intended root before the subprocess is invoked.Evidence
src/fastcontext_mcp/runtime.py:206-217buildstrajfrom user input and only does a lexicalrepo / trajjoin for relative paths.repo_pathas 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
resolved_path.is_relative_to(repo_root)or equivalent.--trajto the subprocess.Regression tests to add
trajectory_path="../outside.jsonl".subdir/../../outside.jsonl.traces/run.jsonland confirm the resolved path stays under the repo root.