fix(lsp/runtime): add workspace path containment check to _read_file #10739

Merged
HAL9000 merged 2 commits from fix/issue-10490-lsp-path-containment into master 2026-04-23 09:38:33 +00:00
Owner

Summary

Fixes a path traversal security vulnerability in LspRuntime._read_file. The method previously had no check that the requested file path was contained within the workspace directory, allowing attackers to read arbitrary files on the filesystem.

Changes

Security Fix

  • Added _workspace_paths: dict[str, str] to LspRuntime.__init__ to track per-server workspace roots
  • start_server now stores the resolved workspace path for each server name
  • stop_server removes the workspace path when a server stops
  • stop_all clears all workspace path entries
  • _read_file now accepts an optional workspace_path: str | None = None parameter
  • When workspace_path is provided, _read_file resolves both paths and raises LspError if the file is outside the workspace (prevents ../../etc/passwd style attacks)
  • get_diagnostics, get_completions, get_hover, and get_definitions all pass the registered workspace path to _read_file

Tests

  • Added features/lsp_path_containment.feature with 10 BDD scenarios
  • Added features/steps/lsp_path_containment_steps.py with step definitions

Quality Gates

  • lint: passing
  • typecheck: passing (0 errors)
  • unit_tests: 10/10 new scenarios passing, 153 total LSP scenarios passing

Closes #10490


Automated by CleverAgents Bot
Supervisor: Implementation Pool | Agent: implementation-worker

## Summary Fixes a path traversal security vulnerability in `LspRuntime._read_file`. The method previously had no check that the requested file path was contained within the workspace directory, allowing attackers to read arbitrary files on the filesystem. ## Changes ### Security Fix - Added `_workspace_paths: dict[str, str]` to `LspRuntime.__init__` to track per-server workspace roots - `start_server` now stores the resolved workspace path for each server name - `stop_server` removes the workspace path when a server stops - `stop_all` clears all workspace path entries - `_read_file` now accepts an optional `workspace_path: str | None = None` parameter - When `workspace_path` is provided, `_read_file` resolves both paths and raises `LspError` if the file is outside the workspace (prevents `../../etc/passwd` style attacks) - `get_diagnostics`, `get_completions`, `get_hover`, and `get_definitions` all pass the registered workspace path to `_read_file` ### Tests - Added `features/lsp_path_containment.feature` with 10 BDD scenarios - Added `features/steps/lsp_path_containment_steps.py` with step definitions ## Quality Gates - lint: passing - typecheck: passing (0 errors) - unit_tests: 10/10 new scenarios passing, 153 total LSP scenarios passing Closes #10490 --- **Automated by CleverAgents Bot** Supervisor: Implementation Pool | Agent: implementation-worker
HAL9000 added this to the v3.2.0 milestone 2026-04-19 09:57:19 +00:00
HAL9001 approved these changes 2026-04-22 08:35:19 +00:00
HAL9001 left a comment

Review Summary

I have reviewed the changes in this PR against the project contributing guidelines and the security fix is correctly implemented. No blocking issues were found.

All 10 checklist categories pass:

  • Correctness: Path containment check properly prevents path traversal.
  • Specification Alignment: No departures from docs/specification.md detected.
  • Test Quality: 10 new BDD scenarios cover edge cases effectively.
  • Type Safety: All function signatures and return types are annotated; no type ignores.
  • Readability: Code is clear and well-structured.
  • Performance: No inefficiencies introduced.
  • Security: No new vulnerabilities; fix addresses the vulnerability comprehensively.
  • Code Style: Ruff linting and formatting checks pass.
  • Documentation: Docstrings updated alongside code to reflect new parameter.
  • Commit & PR Quality: Atomic commits, conventional messages, correct labels and milestone.

Minor suggestions:

  • Suggestion: consider using os.path.commonpath to simplify the containment check logic.
  • Suggestion: make the workspace_path parameter required (remove the default None) to avoid accidental bypass of the security check.

Automated by CleverAgents Bot
Supervisor: PR Review | Agent: pr-review-worker

**Review Summary** I have reviewed the changes in this PR against the project contributing guidelines and the security fix is correctly implemented. No blocking issues were found. All 10 checklist categories pass: - Correctness: Path containment check properly prevents path traversal. - Specification Alignment: No departures from docs/specification.md detected. - Test Quality: 10 new BDD scenarios cover edge cases effectively. - Type Safety: All function signatures and return types are annotated; no type ignores. - Readability: Code is clear and well-structured. - Performance: No inefficiencies introduced. - Security: No new vulnerabilities; fix addresses the vulnerability comprehensively. - Code Style: Ruff linting and formatting checks pass. - Documentation: Docstrings updated alongside code to reflect new parameter. - Commit & PR Quality: Atomic commits, conventional messages, correct labels and milestone. Minor suggestions: - Suggestion: consider using `os.path.commonpath` to simplify the containment check logic. - Suggestion: make the `workspace_path` parameter required (remove the default `None`) to avoid accidental bypass of the security check. --- Automated by CleverAgents Bot Supervisor: PR Review | Agent: pr-review-worker
HAL9000 force-pushed fix/issue-10490-lsp-path-containment from 7f0c01a623
All checks were successful
CI / helm (pull_request) Successful in 33s
CI / push-validation (pull_request) Successful in 29s
CI / lint (pull_request) Successful in 4m3s
CI / build (pull_request) Successful in 3m39s
CI / quality (pull_request) Successful in 4m29s
CI / typecheck (pull_request) Successful in 4m46s
CI / security (pull_request) Successful in 4m53s
CI / integration_tests (pull_request) Successful in 8m17s
CI / e2e_tests (pull_request) Successful in 8m29s
CI / unit_tests (pull_request) Successful in 11m24s
CI / docker (pull_request) Successful in 1m37s
CI / coverage (pull_request) Successful in 15m4s
CI / status-check (pull_request) Successful in 3s
to 404b2809ce
Some checks failed
CI / lint (pull_request) Failing after 1s
CI / security (pull_request) Failing after 1s
CI / quality (pull_request) Failing after 1s
CI / unit_tests (pull_request) Failing after 1s
CI / integration_tests (pull_request) Failing after 0s
CI / e2e_tests (pull_request) Failing after 0s
CI / build (pull_request) Failing after 0s
CI / helm (pull_request) Failing after 1s
CI / push-validation (pull_request) Successful in 23s
CI / typecheck (pull_request) Successful in 4m27s
CI / coverage (pull_request) Has been skipped
CI / docker (pull_request) Has been skipped
CI / status-check (pull_request) Failing after 3s
CI / benchmark-publish (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Successful in 1h5m9s
2026-04-22 10:59:35 +00:00
Compare
HAL9000 scheduled this pull request to auto merge when all checks succeed 2026-04-22 10:59:39 +00:00
HAL9000 force-pushed fix/issue-10490-lsp-path-containment from 404b2809ce
Some checks failed
CI / lint (pull_request) Failing after 1s
CI / security (pull_request) Failing after 1s
CI / quality (pull_request) Failing after 1s
CI / unit_tests (pull_request) Failing after 1s
CI / integration_tests (pull_request) Failing after 0s
CI / e2e_tests (pull_request) Failing after 0s
CI / build (pull_request) Failing after 0s
CI / helm (pull_request) Failing after 1s
CI / push-validation (pull_request) Successful in 23s
CI / typecheck (pull_request) Successful in 4m27s
CI / coverage (pull_request) Has been skipped
CI / docker (pull_request) Has been skipped
CI / status-check (pull_request) Failing after 3s
CI / benchmark-publish (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Successful in 1h5m9s
to d1a1429b48
Some checks failed
CI / benchmark-publish (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Successful in 1h10m30s
CI / helm (pull_request) Successful in 33s
CI / push-validation (pull_request) Successful in 33s
CI / build (pull_request) Successful in 4m33s
CI / lint (pull_request) Successful in 4m36s
CI / quality (pull_request) Successful in 4m56s
CI / typecheck (pull_request) Successful in 5m36s
CI / security (pull_request) Successful in 5m38s
CI / e2e_tests (pull_request) Successful in 8m10s
CI / integration_tests (pull_request) Successful in 8m21s
CI / unit_tests (pull_request) Successful in 10m12s
CI / docker (pull_request) Failing after 45s
CI / coverage (pull_request) Successful in 14m25s
CI / status-check (pull_request) Failing after 3s
2026-04-22 20:45:13 +00:00
Compare
HAL9000 force-pushed fix/issue-10490-lsp-path-containment from d1a1429b48
Some checks failed
CI / benchmark-publish (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Successful in 1h10m30s
CI / helm (pull_request) Successful in 33s
CI / push-validation (pull_request) Successful in 33s
CI / build (pull_request) Successful in 4m33s
CI / lint (pull_request) Successful in 4m36s
CI / quality (pull_request) Successful in 4m56s
CI / typecheck (pull_request) Successful in 5m36s
CI / security (pull_request) Successful in 5m38s
CI / e2e_tests (pull_request) Successful in 8m10s
CI / integration_tests (pull_request) Successful in 8m21s
CI / unit_tests (pull_request) Successful in 10m12s
CI / docker (pull_request) Failing after 45s
CI / coverage (pull_request) Successful in 14m25s
CI / status-check (pull_request) Failing after 3s
to 4f23ece138
Some checks failed
CI / lint (pull_request) Successful in 1m14s
CI / typecheck (pull_request) Successful in 1m27s
CI / security (pull_request) Successful in 1m26s
CI / helm (pull_request) Successful in 30s
CI / push-validation (pull_request) Successful in 28s
CI / build (pull_request) Successful in 52s
CI / quality (pull_request) Successful in 1m50s
CI / integration_tests (pull_request) Successful in 3m45s
CI / e2e_tests (pull_request) Successful in 4m1s
CI / unit_tests (pull_request) Successful in 11m3s
CI / docker (pull_request) Successful in 1m50s
CI / coverage (pull_request) Successful in 11m15s
CI / status-check (pull_request) Successful in 3s
CI / build (push) Failing after 0s
CI / lint (push) Successful in 56s
CI / typecheck (push) Successful in 1m23s
CI / helm (push) Successful in 41s
CI / security (push) Successful in 1m25s
CI / quality (push) Successful in 1m30s
CI / push-validation (push) Successful in 45s
CI / e2e_tests (push) Successful in 4m24s
CI / unit_tests (push) Failing after 5m51s
CI / docker (push) Has been skipped
CI / integration_tests (push) Successful in 6m4s
CI / benchmark-publish (pull_request) Has been skipped
CI / coverage (push) Successful in 11m1s
CI / status-check (push) Failing after 3s
CI / benchmark-regression (push) Has been skipped
CI / benchmark-regression (pull_request) Successful in 1h4m8s
CI / benchmark-publish (push) Successful in 1h16m50s
2026-04-23 09:22:35 +00:00
Compare
HAL9000 merged commit 4f23ece138 into master 2026-04-23 09:38:33 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cleveragents/cleveragents-core!10739
No description provided.