fix(bundle): reject path traversal in import (CVE-2007-4559, #9) - #24
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds path-safety checks for tar member names and manifest paths (rejecting empty, absolute, NUL, or ChangesBundle Path Traversal Security Fix
Sequence DiagramsequenceDiagram
participant Client
participant import_apply
participant import_check
participant _safe_member_path
participant KBDir
Client->>import_apply: request import-apply(bundle)
import_apply->>import_check: validate manifest entries
import_check->>_safe_member_path: resolve member name -> dest
_safe_member_path-->>import_check: dest path or raise RuntimeError
alt issues found
import_check-->>import_apply: issues, ok=False
import_apply-->>Client: raise RuntimeError (abort)
else ok
import_apply->>_safe_member_path: resolve extraction destinations
_safe_member_path-->>KBDir: resolved safe path
import_apply->>Client: success
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
tests/test_bundle.py (1)
121-126: 💤 Low valueConsider case-insensitive string matching for robustness.
The substring check uses lowercase
"traversal"and"unsafe", which could fail if the implementation's error messages use different casing (e.g., "Path traversal" or "Unsafe path"). Since tests pass now, this is fine, but a case-insensitive check would be more resilient to future message changes.♻️ Suggested improvement
- assert any("traversal" in i or "unsafe" in i for i in result.issues) + assert any("traversal" in i.lower() or "unsafe" in i.lower() for i in result.issues)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/test_bundle.py` around lines 121 - 126, The test test_import_check_flags_path_traversal currently checks result.issues for substrings "traversal" or "unsafe" using a case-sensitive match; make this resilient by performing a case-insensitive check: iterate over result.issues and compare lowercase forms (e.g., use i.lower() and check for "traversal" or "unsafe") so messages like "Path traversal" or "Unsafe path" are matched; update the assertion that inspects result.issues in the test to use this lowercase comparison.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@tests/test_bundle.py`:
- Around line 121-126: The test test_import_check_flags_path_traversal currently
checks result.issues for substrings "traversal" or "unsafe" using a
case-sensitive match; make this resilient by performing a case-insensitive
check: iterate over result.issues and compare lowercase forms (e.g., use
i.lower() and check for "traversal" or "unsafe") so messages like "Path
traversal" or "Unsafe path" are matched; update the assertion that inspects
result.issues in the test to use this lowercase comparison.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: a2bda4bd-6824-4299-9a18-9916ed7e0915
📒 Files selected for processing (3)
CHANGELOG.mdsrc/vouch/bundle.pytests/test_bundle.py
|
Hi @plind-junior Could you plz review this PR and share any feedback? Thanks |
|
Nice. The resolve + The repro test is the right kind: it builds the actual attacker bundle and asserts the canary never appears. A few small things, none blocking:
LGTM once the export side uses the same predicate. |
|
Thanks for your feedback. Addressed the centralization point : both |
|
LTGM! |
fix(bundle): reject path traversal in import (CVE-2007-4559, #9)
What changed
bundle.import_applynow resolves each tar member path underkb_dirand rejects any name that escapes it via../, an absolute path, or a NUL byte. The same check is applied inimport_checkandexport_checkso malicious bundles fail at the diff and verify stages too. A new_safe_member_path()helper centralizes the logic.Why
Fixes #9
Bundle import joined attacker-controlled tar member names directly onto
kb_dir(CVE-2007-4559) - a crafted.tar.gzwith a member named../../evil.txtcould write anywhere the process had permission. The pre-existing manifest allow-list did not help, because the manifest lives inside the same attacker-controlled tarball.What might break
Nothing for existing users:
kb.*method changes signature or default behavior on well-formed bundles.RuntimeErrorinstead of silently extracting - which is the fix.Not a surface change.
VEP
Tests
make checkpasses locally (lint + mypy + pytest) - 57/57 passing, ruff cleantests/test_bundle.py:test_import_apply_rejects_path_traversalreproduces the../../evil.txtattack from the issuetest_import_apply_rejects_absolute_pathcovers the/abs/pathvarianttest_import_check_flags_path_traversalconfirms the diff phase reports itCHANGELOG.mdupdated under## [Unreleased]Summary by CodeRabbit
Bug Fixes
Tests
Documentation