d08084236a
LspRuntime._read_file had no check that the requested file path was contained within the workspace directory, allowing path traversal attacks to read arbitrary files on the filesystem. Changes: - Add _workspace_paths dict to LspRuntime to track per-server workspace roots - start_server now stores the resolved workspace path for each server - stop_server and stop_all clean up workspace path entries - _read_file now accepts an optional workspace_path parameter; when provided, it resolves both paths and raises LspError if the file is outside the workspace (prevents ../../etc/passwd style attacks) - get_diagnostics, get_completions, get_hover, get_definitions all pass the registered workspace path to _read_file - Add features/lsp_path_containment.feature with 10 BDD scenarios - Add features/steps/lsp_path_containment_steps.py step definitions ISSUES CLOSED: #10490
84 lines
4.7 KiB
Gherkin
84 lines
4.7 KiB
Gherkin
Feature: LspRuntime workspace path containment
|
|
As a security-conscious platform
|
|
I need LspRuntime._read_file to enforce workspace path containment
|
|
So that path traversal attacks cannot read files outside the workspace
|
|
|
|
# ── _read_file static method containment ──────────────────────────
|
|
|
|
Scenario: read_file allows a file inside the workspace
|
|
Given lspc I have a temp workspace directory
|
|
And lspc I have a file inside the workspace with content "safe content"
|
|
When lspc I call read_file with the workspace path
|
|
Then lspc the file content should be "safe content"
|
|
And lspc no error should be raised
|
|
|
|
Scenario: read_file blocks a file outside the workspace
|
|
Given lspc I have a temp workspace directory
|
|
And lspc I have a file outside the workspace
|
|
When lspc I call read_file with the workspace path
|
|
Then lspc an LspError should be raised with message containing "outside workspace"
|
|
|
|
Scenario: read_file blocks path traversal using dot-dot segments
|
|
Given lspc I have a temp workspace directory
|
|
And lspc I have a file outside the workspace
|
|
When lspc I call read_file with a traversal path and the workspace path
|
|
Then lspc an LspError should be raised with message containing "outside workspace"
|
|
|
|
Scenario: read_file without workspace path has no containment check
|
|
Given lspc I have a file outside the workspace
|
|
When lspc I call read_file without a workspace path
|
|
Then lspc no error should be raised
|
|
|
|
# ── get_diagnostics containment ────────────────────────────────────
|
|
|
|
Scenario: get_diagnostics blocks file outside workspace
|
|
Given lspc I have a temp workspace directory
|
|
And lspc I have a file outside the workspace
|
|
And lspc I create an LspRuntime with a healthy mock server "local/pyright" and workspace
|
|
When lspc I try to get diagnostics for "local/pyright" on the outside file
|
|
Then lspc an LspError should be raised with message containing "outside workspace"
|
|
|
|
Scenario: get_diagnostics allows file inside workspace
|
|
Given lspc I have a temp workspace directory
|
|
And lspc I have a file inside the workspace with content "x = 1"
|
|
And lspc I create an LspRuntime with a healthy mock server "local/pyright" and workspace
|
|
When lspc I get diagnostics for "local/pyright" on the inside file
|
|
Then lspc diagnostics should be returned as a list
|
|
And lspc no error should be raised
|
|
|
|
# ── get_completions containment ────────────────────────────────────
|
|
|
|
Scenario: get_completions blocks file outside workspace
|
|
Given lspc I have a temp workspace directory
|
|
And lspc I have a file outside the workspace
|
|
And lspc I create an LspRuntime with a healthy mock server "local/pyright" and workspace
|
|
When lspc I try to get completions for "local/pyright" on the outside file at line 1 column 1
|
|
Then lspc an LspError should be raised with message containing "outside workspace"
|
|
|
|
# ── get_hover containment ──────────────────────────────────────────
|
|
|
|
Scenario: get_hover blocks file outside workspace
|
|
Given lspc I have a temp workspace directory
|
|
And lspc I have a file outside the workspace
|
|
And lspc I create an LspRuntime with a healthy mock server "local/pyright" and workspace
|
|
When lspc I try to get hover for "local/pyright" on the outside file at line 1 column 1
|
|
Then lspc an LspError should be raised with message containing "outside workspace"
|
|
|
|
# ── get_definitions containment ────────────────────────────────────
|
|
|
|
Scenario: get_definitions blocks file outside workspace
|
|
Given lspc I have a temp workspace directory
|
|
And lspc I have a file outside the workspace
|
|
And lspc I create an LspRuntime with a healthy mock server "local/pyright" and workspace
|
|
When lspc I try to get definitions for "local/pyright" on the outside file at line 1 column 1
|
|
Then lspc an LspError should be raised with message containing "outside workspace"
|
|
|
|
# ── workspace path not registered ─────────────────────────────────
|
|
|
|
Scenario: get_diagnostics without registered workspace has no containment check
|
|
Given lspc I have a file outside the workspace
|
|
And lspc I create an LspRuntime with a healthy mock server "local/pyright" without workspace
|
|
When lspc I get diagnostics for "local/pyright" on the outside file
|
|
Then lspc diagnostics should be returned as a list
|
|
And lspc no error should be raised
|