Skip to content

feat(security): path traversal protection — PathRefusalError, realpath confinement, MCP + guard integration (closes #58 phase-1)#131

Merged
Wolfvin merged 1 commit into
mainfrom
feat/issue-58-path-traversal-phase-1
Jul 1, 2026
Merged

feat(security): path traversal protection — PathRefusalError, realpath confinement, MCP + guard integration (closes #58 phase-1)#131
Wolfvin merged 1 commit into
mainfrom
feat/issue-58-path-traversal-phase-1

Conversation

@Wolfvin

@Wolfvin Wolfvin commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Summary

Implements Phase 1 of issue #58 — path traversal protection for CodeLens.

CodeLens reads source files from a workspace directory. When the workspace path — or any file path derived from agent-supplied input — is naively joined with os.path.join and opened, a malicious or buggy caller can escape the workspace via:

  • Relative traversal: ../../etc/passwd
  • Symlinks inside the workspace that point outside it
  • Absolute paths: /etc/passwd
  • Sibling-prefix collision: /home/proj-evil vs /home/proj

This PR implements symlink-aware path confinement to the project root using os.path.realpath on both sides, defeating symlink-based escapes by comparing real on-disk locations.

Files

New:

  • scripts/security/__init__.py — package init, re-exports public API
  • scripts/security/path_traversal.pyPathRefusalError, resolve_path_within_project(), is_path_within_project(), safe_resolve_path()
  • tests/test_path_traversal.py — 41 tests covering symlink escapes, sibling-prefix collision, dotdot traversal, MCP-side validation

Modified:

  • scripts/utils.py — added safe_read_file_within_project() wrapper (degrades gracefully if security package unavailable)
  • scripts/commands/guard.py_analyze_file now uses safe_read_file_within_project
  • scripts/mcp_server.py_execute_command calls _validate_path_args before dispatching; refuses file/path/file_path args that escape workspace, returns structured path_refusal error so agents can self-correct

Key design decisions

  1. os.path.realpath on both project root and candidate path — defeats symlink-based escapes by comparing real on-disk locations.
  2. Trailing separator on project root_normalize_project_root appends os.sep so startswith() respects path-segment boundaries (defeats /home/proj-evil vs /home/proj collision).
  3. PathRefusalError inherits PermissionError — existing except OSError / except PermissionError handlers in callers continue to catch it without modification.
  4. Graceful degradation — if scripts/security/ is unavailable (older install), safe_read_file_within_project falls back to legacy safe_read_file rather than crashing.
  5. MCP-side structured error — refusals return {"status":"error","error":"path_refusal","message":...,"suggestion":...} so AI agents get actionable feedback.

Acceptance criteria

  • Path traversal: symlink outside project root is refused
  • Symlink that stays inside project is allowed
  • .. traversal that escapes is refused
  • Sibling-prefix collision (proj-evil vs proj) is refused
  • MCP tools returning file content refuse path-traversing args
  • PathRefusalError exception class exists and is PermissionError subclass

(Phases 2–7 — config secret redaction, git safety guard, Secretlint, file system MCP tools, LLM schema validation, PoC generation — are out of scope for this Phase 1 PR.)

Test results

  • 41 new tests in tests/test_path_traversal.py — all pass
  • tests/test_command_registry.py + tests/test_command_count.py — all pass (no command count change in this PR)
  • No regressions in existing test suite (verified 1239 passed, 15 skipped, 4 pre-existing upstream failures deselected)

Verified git apply cleanly against Wolfvin/CodeLens@main.

Closes #58 (phase-1).

…h confinement, MCP + guard integration (closes #58 phase-1)
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@sonarqubecloud

sonarqubecloud Bot commented Jul 1, 2026

Copy link
Copy Markdown

@Wolfvin Wolfvin merged commit 16caff1 into main Jul 1, 2026
4 of 10 checks passed
@Wolfvin Wolfvin deleted the feat/issue-58-path-traversal-phase-1 branch July 1, 2026 05:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Security & safety hardening — path traversal, config secret redaction, git safety guard, Secretlint

1 participant