Skip to content

security: confine model context reads to the cloned repository - #9

Open
harshitethic wants to merge 4 commits into
mainfrom
security/confine-repository-context
Open

harshitethic wants to merge 4 commits into
mainfrom
security/confine-repository-context

Conversation

@harshitethic

Copy link
Copy Markdown
Owner

Problem

PatchPilot builds the model's repository context by walking the cloned worktree and reading selected files. The existing implementation checked ignored directory names but did not enforce that a discovered path still resolved inside the clone.

That means an untrusted repository could include a file symlink such as:

repo/
  src/
  leaked.txt -> /home/user/.ssh/config

Path.is_file() follows file symlinks, so list_files() could include leaked.txt. Later, read_repo_context() opened repo / "leaked.txt", which follows the same symlink and could place host-side content into the prompt sent to Ollama/OpenAI/OpenRouter.

The edit path already had a repository-containment check, but the read/context path did not, so the security boundary was inconsistent.

Fix

Introduce one resolved-path boundary for automatic repository reads:

  • resolve candidate paths against the cloned repository root;
  • reject paths whose resolved target is outside that root;
  • apply the check during file discovery;
  • apply it again immediately before context reads (defense in depth);
  • read from the already validated resolved path rather than re-following the original symlink;
  • evaluate ignored directories relative to the repository instead of against absolute host path components.

Internal symlinks that resolve to files inside the repository remain usable. External symlinks and explicit parent-path escapes are excluded.

Regression coverage

Adds focused tests for:

  1. a discovered file symlink whose target is outside the repository;
  2. a direct ../secret.txt context-read attempt;
  3. an externally resolving symlink passed directly to read_repo_context(), proving the second boundary works independently of discovery;
  4. a normal in-repository source file, ensuring legitimate context collection still works.

Symlink-specific tests skip only on platforms where creating symlinks is unavailable.

Security scope

This PR protects the repository-context → model prompt boundary. It prevents context collection from following repository paths to host files outside the cloned worktree.

It does not claim to sandbox test execution or arbitrary repository code. PatchPilot still needs container/VM isolation, resource limits, network policy, and secret isolation before being exposed to untrusted multi-user workloads; the README continues to state that explicitly.

Documentation

The security model now documents that repository context is restricted to resolved paths inside the clone before contents are sent to the configured model.

Changed files

  • backend/app/main.py — resolved repository-path validation + guarded discovery/read path
  • backend/tests/test_main.py — four regression/behavior tests
  • README.md — documented context-confinement guarantee

Validation notes

This branch is based directly on current main and is isolated from the other open PatchPilot fixes. The diff is 3 files and keeps the public API unchanged.

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.

1 participant