🛡️ Sentinel: [CRITICAL] Fix path traversal in dependency extractor#260
🛡️ Sentinel: [CRITICAL] Fix path traversal in dependency extractor#260bashandbone wants to merge 1 commit into
Conversation
This commit fixes a path traversal vulnerability in `crates/flow/src/incremental/extractors/typescript.rs`. The manual path normalization fallback incorrectly popped `RootDir` and `Prefix` components when encountering `..` (`ParentDir`). The fix prevents popping root components and correctly preserves leading `..` for valid relative paths. Co-authored-by: bashandbone <89049923+bashandbone@users.noreply.github.com>
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
Reviewer's guide (collapsed on small PRs)Reviewer's GuideFixes a critical path traversal vulnerability in the TypeScript dependency extractor’s manual path normalization, and documents the issue and remediation guidance in a Sentinel security note. File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Pull request overview
This PR hardens the TypeScript dependency extractor’s fallback path normalization to prevent .. components from escaping an absolute path’s RootDir/Prefix, addressing a path traversal risk when canonicalize() fails. It also adds Sentinel documentation capturing the incident and guidance for safe manual canonicalization.
Changes:
- Update manual
components()-based normalization to avoid poppingRootDir/Prefixand to preserve leading/consecutive..for relative paths. - Add a Sentinel incident note documenting the vulnerability, root cause, and prevention guidance.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| crates/flow/src/incremental/extractors/typescript.rs | Hardens .. handling in the canonicalize() fallback normalization logic. |
| .jules/sentinel.md | Adds security incident documentation for the path traversal issue and prevention guidance. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // SECURITY: Prevent path traversal from escaping root or prefix | ||
| match components.last() { | ||
| Some(std::path::Component::Prefix(_)) | Some(std::path::Component::RootDir) => {} | ||
| Some(std::path::Component::ParentDir) | None => { components.push(component); } | ||
| _ => { components.pop(); } | ||
| } |
| ## 2024-05-24 - Path Traversal in Dependency Extractor | ||
| **Vulnerability:** A path traversal vulnerability (sandbox escape/arbitrary file read risk) existed in the TypeScript module resolver's fallback path normalization logic (`crates/flow/src/incremental/extractors/typescript.rs`). | ||
| **Learning:** When `std::path::PathBuf::canonicalize` fails (e.g., file not found during static analysis), the manual fallback normalization blindly called `components.pop()` when encountering `Component::ParentDir` (`..`). This allowed an attacker or malformed file to pass `../../etc/passwd`, causing `..` to pop the root directory (`/`), effectively turning an absolute path into a relative one that bypassed the configured base directory bounds when subsequently joined. Furthermore, it improperly handled consecutive leading `..` components by ignoring them. | ||
| **Prevention:** When manually implementing path canonicalization using `std::path::Components`, always match against the current `components.last()`. Explicitly prevent `Component::ParentDir` from popping `Component::RootDir` or `Component::Prefix(_)`. If the list is empty or the last component is already `Component::ParentDir`, the new `ParentDir` must be pushed instead of popped to correctly maintain valid relative paths. |
| @@ -0,0 +1,4 @@ | |||
| ## 2024-05-24 - Path Traversal in Dependency Extractor | |||
🚨 Severity: CRITICAL
💡 Vulnerability: The fallback path normalization logic in the TypeScript dependency extractor (
crates/flow/src/incremental/extractors/typescript.rs) incorrectly handledComponent::ParentDir(..). It blindly popped the last component from the path. This allowed..to pop the root directory (/), effectively allowing an attacker to pass an absolute path like/../../etc/passwdthat would strip the root and become a relative traversal path, potentially bypassing directory bound checks. It also failed to correctly preserve multiple consecutive leading..segments for valid relative paths.🎯 Impact: Sandbox escape and arbitrary file access risk during static analysis if the analyzer processes malformed or malicious relative imports that attempt to traverse out of the base directory.
🔧 Fix: Updated the manual path resolution loop to properly match
components.last(). It explicitly preventsParentDirfrom poppingRootDirorPrefix. If the list is empty or already ends with aParentDir, the newParentDiris pushed, properly maintaining valid relative paths (../../foo) while preventing escapes.✅ Verification: Ensure tests pass locally by running
cargo test -p thread-flow. Verified building without clippy warnings usingcargo clippy -p thread-flow -- -D warnings.PR created automatically by Jules for task 13040705844836331622 started by @bashandbone
Summary by Sourcery
Fix unsafe manual path normalization in the TypeScript dependency extractor to prevent path traversal escapes and document the incident in Sentinel notes.
Bug Fixes:
Documentation: