-
Notifications
You must be signed in to change notification settings - Fork 0
🛡️ Sentinel: [HIGH] Fix path traversal in manual TS module path resolution #161
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 |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| ## 2025-05-15 - [Path Traversal in Manual Path Normalization] | ||
| **Vulnerability:** Manual path resolution using `components.pop()` on `std::path::Component::ParentDir` allowed path traversal. If a path like `../../a` was parsed, `components.pop()` on an empty `Vec` did nothing, turning the path into `a` instead of preserving the parent traversal. It could also pop `RootDir` or `Prefix` components, changing absolute paths to relative ones or traversing beyond intended roots. | ||
| **Learning:** `std::path::Component` normalization must handle empty lists and consecutive `ParentDir` components by pushing them instead of ignoring them. It must also explicitly avoid popping `RootDir` or `Prefix` components to prevent escaping virtual file systems or simulated root directories. | ||
| **Prevention:** Explicitly check if the `components` list is empty, if the last component is `ParentDir`, or if the last component is `RootDir` / `Prefix` before calling `pop()`. | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -808,7 +808,18 @@ impl TypeScriptDependencyExtractor { | |||||||||||||||||||||
| for component in resolved.components() { | ||||||||||||||||||||||
| match component { | ||||||||||||||||||||||
| std::path::Component::ParentDir => { | ||||||||||||||||||||||
| components.pop(); | ||||||||||||||||||||||
| let is_empty = components.is_empty(); | ||||||||||||||||||||||
| let last_is_parent = matches!(components.last(), Some(std::path::Component::ParentDir)); | ||||||||||||||||||||||
| let last_is_root_or_prefix = matches!( | ||||||||||||||||||||||
| components.last(), | ||||||||||||||||||||||
| Some(std::path::Component::RootDir) | Some(std::path::Component::Prefix(_)) | ||||||||||||||||||||||
|
Comment on lines
+812
to
+815
|
||||||||||||||||||||||
| let last_is_parent = matches!(components.last(), Some(std::path::Component::ParentDir)); | |
| let last_is_root_or_prefix = matches!( | |
| components.last(), | |
| Some(std::path::Component::RootDir) | Some(std::path::Component::Prefix(_)) | |
| let last_is_parent = | |
| matches!(components.last(), Some(&std::path::Component::ParentDir)); | |
| let last_is_root_or_prefix = matches!( | |
| components.last(), | |
| Some(&std::path::Component::RootDir) | |
| | Some(&std::path::Component::Prefix(_)) |
Copilot
AI
Apr 19, 2026
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.
This change fixes tricky .. normalization edge cases, but there are no tests covering the newly handled scenarios (leading ../../... that should remain relative, and .. following RootDir/Prefix that must not pop them). Please add unit tests exercising these cases so the security fix can’t regress silently; the existing resolve_module_path tests in crates/flow/tests/extractor_typescript_tests.rs can be extended with a couple of dedicated cases.
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.
New markdown files in this repo typically include an SPDX header (often via an HTML comment block) or are covered by a
REUSE.tomlannotation. This file currently has no SPDX metadata and appears not to be covered by the existingREUSE.tomlannotations, which can cause thefsfe/reuse-actionCI job to fail. Add an SPDX header to this file or extendREUSE.tomlto cover.jules/**.