-
Notifications
You must be signed in to change notification settings - Fork 1
test: path traversal adversarial corpus + prompt trust annotation #74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -346,6 +346,91 @@ def test_read_file_rejects_prefix_bypass(self, tmp_path: Path) -> None: | |
| assert "path traversal not allowed" in result.lower() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔵 LOW: Extensive adversarial path traversal corpus added to testsConfidence: 95% A new class of parametrized tests for adversarial path traversal was added, covering Unix/Windows traversal, absolute/symlink paths, and null byte handling. These tests validate that the core path safety checks in Suggestion: Continue maintaining and expanding these adversarial path tests as new codebase access features are introduced, and adapt them if rejection logic changes. Periodically audit for new traversal patterns or bypasses as the code or OS support evolves. — Not wrong, but there's a simpler way. Still�3this hardening is worth the slight verbosity. |
||
|
|
||
|
|
||
| class TestPathTraversalAdversarialCorpus: | ||
| """F-CB-002: Adversarial path corpus for read_file and list_files. | ||
|
|
||
| Curated traversal inputs beyond the basic ../../etc/passwd case. | ||
| Each test verifies the Path.is_relative_to() guard rejects the | ||
| input or the path resolves safely inside the repo root. | ||
| """ | ||
|
|
||
| @pytest.mark.parametrize( | ||
| "path", | ||
| [ | ||
| "../../etc/passwd", | ||
| "../../../etc/shadow", | ||
| "..\\..\\windows\\system32\\config\\sam", | ||
| "src/../../../etc/passwd", | ||
| "/etc/passwd", | ||
| "/tmp/evil.py", | ||
| ], | ||
| ids=[ | ||
| "unix-traversal-2", | ||
| "unix-traversal-3", | ||
| "windows-backslash", | ||
| "mid-path-breakout", | ||
| "absolute-unix", | ||
| "absolute-tmp", | ||
| ], | ||
| ) | ||
| def test_read_file_rejects_traversal_corpus(self, tmp_repo: Path, path: str) -> None: | ||
| read_fn = _make_read_file(tmp_repo) | ||
| result = read_fn(path) | ||
| assert ( | ||
| "not allowed" in result.lower() | ||
| or "not found" in result.lower() | ||
| or "error" in result.lower() | ||
| ) | ||
|
|
||
| @pytest.mark.parametrize( | ||
| "path", | ||
| [ | ||
| "../..", | ||
| "/etc", | ||
| "/tmp", | ||
| "src/../../..", | ||
| ], | ||
| ids=[ | ||
| "dir-traversal", | ||
| "absolute-etc", | ||
| "absolute-tmp", | ||
| "mid-path-dir-breakout", | ||
| ], | ||
| ) | ||
| def test_list_files_rejects_traversal_corpus(self, tmp_repo: Path, path: str) -> None: | ||
| list_fn = _make_list_files(tmp_repo) | ||
| result = list_fn(path) | ||
| assert ( | ||
| "not allowed" in result.lower() | ||
| or "not found" in result.lower() | ||
| or "error" in result.lower() | ||
| ) | ||
|
|
||
| def test_symlink_traversal_blocked(self, tmp_path: Path) -> None: | ||
| """Symlink pointing outside repo root is rejected.""" | ||
| repo_root = tmp_path / "repo" | ||
| repo_root.mkdir() | ||
| (repo_root / "safe.py").write_text("safe") | ||
|
|
||
| outside = tmp_path / "outside_secret.py" | ||
| outside.write_text("stolen data") | ||
|
|
||
| link = repo_root / "evil_link.py" | ||
| link.symlink_to(outside) | ||
|
|
||
| read_fn = _make_read_file(repo_root) | ||
| result = read_fn("evil_link.py") | ||
| # resolve() follows the symlink — is_relative_to() should catch it | ||
| assert "not allowed" in result.lower() | ||
|
|
||
| def test_null_byte_in_path(self, tmp_repo: Path) -> None: | ||
| """Path with null byte doesn't crash (handled by OS or Python).""" | ||
| read_fn = _make_read_file(tmp_repo) | ||
| result = read_fn("src/main\x00.py") | ||
| # Should produce an error, not succeed | ||
| assert "error" in result.lower() or "not found" in result.lower() | ||
|
|
||
|
|
||
| # --- list_files tool tests --- | ||
|
|
||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔵 LOW: Prompt trust annotation updated for file context
Confidence: 93%
The documentation for file context in the primary system prompt has been updated: file context is now clearly annotated as non-privileged reference material rather than trusted input. This is important for prompt governance, as it enforces clear trust boundaries between sources of evidence used in analysis versus privileged, version-controlled configuration.
Suggestion: Make sure all tooling and documentation referencing 'file context' reflect this annotation. Continue differentiating between trusted and non-trusted sources across documentation to avoid privilege escalation vulnerabilities via prompt injection.
— Minor governance note. Not blocking. The rules say trust, you say reference. Reference is safer.