fix(mcp): jail LLM source excerpt reads - #151
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
Pull request overview
This PR hardens loomweave-mcp against prompt-time local file exfiltration by re-validating stored source_file_path values at use time, ensuring they cannot escape the project root (including via symlinks), and surfacing a stable invalid-path MCP error when validation fails.
Changes:
- Introduces an enum
SourceExcerptErrorwith anInvalidPathvariant and maps excerpt failures to appropriateMcpErrorCodes. - Jails source excerpt reads by normalizing/canonicalizing paths against the canonical project root before reading file contents.
- Adds a regression test that poisons the catalogue with an outside-project path and asserts the tool fails with
invalid-pathand does not invoke the LLM provider.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| crates/loomweave-mcp/src/lib.rs | Adds InvalidPath error variant and applies normalize_source_path when building source excerpts to prevent out-of-root reads. |
| crates/loomweave-mcp/src/tools/summary.rs | Plumbs project_root through summary + inferred-edge prompt construction so excerpt reads are jailed. |
| crates/loomweave-mcp/src/tools/status.rs | Ensures token-estimation path for summaries uses the jailed excerpt read. |
| crates/loomweave-mcp/tests/storage_tools.rs | Adds a regression test asserting outside-project catalogue paths fail closed with invalid-path and no provider invocation. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| let path = | ||
| normalize_source_path(project_root, path).map_err(|_| SourceExcerptError::InvalidPath { | ||
| entity_id: entity.id.clone(), | ||
| })?; |
|
Superseded by the rebase onto |
Motivation
source_file_pathvalues at use time against the canonical project root.Description
SourceExcerptErrorstruct with an enumSourceExcerptErrorthat adds anInvalidPathvariant and maps errors to appropriateMcpErrorCodes.normalize_source_pathusage and canonicalization inverified_source_excerpt(project_root, entity)to jail every file read and reject absolute/../symlink-escaped paths outside the project root.verified_source_excerpt(&self.project_root, &entity)signature through summary and inferred-edge prompt construction (src/tools/summary.rs,src/tools/status.rs) so all LLM prompt paths are validated before reading.summary_cold_miss_refuses_catalogue_path_outside_projectthat poisons the catalogue with an outside-projectsource_file_pathand asserts the summary call returns aninvalid-pathenvelope and does not invoke the provider.Testing
cargo fmt --all -- --checkwhich succeeded.cargo test -p loomweave-mcp summary_cold_miss_refuses_catalogue_path_outside_projectwhich passed and the new regression test succeeded.cargo test -p loomweave-mcpwhich showed all 124 library tests passed, but one unrelated lifecycle test failed due to a grandchild process timing issue (the failure is unrelated to the code changes and is preserved as observed).git diff --checkand formatting diffs were clean.Codex Task