If your MCP server exposes a read_file / write_file / list_dir tool, it is one clever prompt away from serving /etc/passwd to whoever controls the model's input. The naive fixes — prefix checks, os.path.normpath, stripping .. — all fail against symlinks and absolute paths. Here is a guard that holds, plus the regression test that keeps it holding.
Why the obvious fixes leak
# BROKEN 1: prefix check on the raw string
if not user_path.startswith(BASE): # "/base/../etc/passwd".startswith("/base") is True
reject()






