Skip to content

🛡️ Sentinel: [CRITICAL/HIGH] Fix path traversal in manual path normalization#240

Open
bashandbone wants to merge 1 commit into
mainfrom
sentinel-fix-path-traversal-normalization-5611789745888416068
Open

🛡️ Sentinel: [CRITICAL/HIGH] Fix path traversal in manual path normalization#240
bashandbone wants to merge 1 commit into
mainfrom
sentinel-fix-path-traversal-normalization-5611789745888416068

Conversation

@bashandbone
Copy link
Copy Markdown
Contributor

@bashandbone bashandbone commented May 17, 2026

🚨 Severity: HIGH
💡 Vulnerability: When a path could not be resolved using standard canonicalization (e.g., an unresolved module import), the manual path resolution logic naively handled ../ by popping the last element from an intermediate stack. This meant components.pop() could inadvertently remove a root directory (/) or a volume prefix, effectively turning absolute file paths into relative ones, or failing to preserve valid relative paths (../../a). This opened the door for potential Path Traversal vulnerabilities during module extractions.
🎯 Impact: An attacker or misconfigured malicious file could potentially exploit ../ strings to bypass directory boundaries or access files outside the expected context during analysis.
🔧 Fix: Adjusted the manual normalization loop to ensure ParentDir safely collapses Normal components. It explicitly blocks popping RootDir and Prefix, and handles contiguous ParentDir stack sequences safely.
Verification:

  1. Ran cargo clippy --workspace -- -D warnings.
  2. Verified cargo test -p thread-flow --test extractor_typescript_tests.
  3. Created required Sentinel log entry.

PR created automatically by Jules for task 5611789745888416068 started by @bashandbone

Summary by Sourcery

Harden manual path normalization in the TypeScript dependency extractor to prevent unsafe parent directory handling and document the resolved vulnerability in Sentinel logs.

Bug Fixes:

  • Prevent manual path normalization from popping root or prefix components when resolving ParentDir, avoiding potential path traversal and incorrect absolute-to-relative path conversions.

Documentation:

  • Add a Sentinel incident entry documenting the path traversal vulnerability, root cause, and recommended safe ParentDir handling pattern.

…zation

Implemented safe path normalization during unresolved module resolution
in `crates/flow/src/incremental/extractors/typescript.rs` to correctly
handle `std::path::Component::ParentDir`. Prevented popping `RootDir`
or `Prefix`, protecting against converting absolute paths to relative
paths or unauthorized directory traversal.

Added security journal entry detailing the manual normalization
vulnerability in `.jules/sentinel.md`.

Co-authored-by: bashandbone <89049923+bashandbone@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 17, 2026 17:55
@google-labs-jules
Copy link
Copy Markdown
Contributor

👋 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 @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented May 17, 2026

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Adjusts manual path normalization in the TypeScript dependency extractor to safely handle ParentDir components and prevent path traversal, and records the security fix and guidance in Sentinel documentation.

File-Level Changes

Change Details Files
Harden manual path normalization to prevent unsafe collapsing of ParentDir components that could lead to path traversal.
  • Replace naive components.pop() on ParentDir with logic that inspects the last stacked component before acting
  • Preserve leading ParentDir segments or empty-stack cases by pushing ParentDir instead of popping
  • Prevent popping RootDir or Prefix components so absolute paths cannot be converted into relative paths
  • Allow ParentDir to collapse only preceding Normal components while keeping other components intact
crates/flow/src/incremental/extractors/typescript.rs
Document the identified path traversal vulnerability and the safe ParentDir handling pattern in Sentinel logs.
  • Add a Sentinel entry describing the original vulnerability in manual path normalization
  • Capture the key learning about careful ParentDir state handling in Rust path normalization
  • Record a prevention pattern specifying the robust component popping logic for future implementations
.jules/sentinel.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses a high-severity path traversal risk in the TypeScript incremental dependency extractor by hardening the manual path normalization fallback used when canonicalize() fails.

Changes:

  • Hardened manual ../ handling to avoid popping RootDir/Prefix and to preserve contiguous ParentDir sequences safely.
  • Added a Sentinel security log entry documenting the vulnerability, learning, and prevention guidance.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
crates/flow/src/incremental/extractors/typescript.rs Fixes manual path normalization logic to prevent unsafe component popping during unresolved module resolution.
.jules/sentinel.md Adds Sentinel entry documenting the vulnerability and prevention guidance.
Comments suppressed due to low confidence (1)

crates/flow/src/incremental/extractors/typescript.rs:829

  • The updated manual ParentDir normalization fixes subtle boundary cases, but there are no unit tests covering the newly-handled scenarios (e.g., more .. segments than available Normal components so .. must be preserved, and ensuring RootDir/Prefix are never removed). Please add regression tests around resolve_module_path for these edge cases so this security fix doesn’t regress.
                // If canonicalize fails (file doesn't exist), manually resolve
                let mut components = Vec::new();
                for component in resolved.components() {
                    match component {
                        std::path::Component::ParentDir => {
                            if let Some(c) = components.last() {
                                if c == &std::path::Component::ParentDir {
                                    components.push(component);
                                } else if !matches!(
                                    c,
                                    std::path::Component::RootDir | std::path::Component::Prefix(_)
                                ) {
                                    components.pop();
                                }
                            } else {
                                components.push(component);
                            }
                        }
                        std::path::Component::CurDir => {}
                        _ => components.push(component),
                    }
                }
                resolved = components.iter().collect();
            }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .jules/sentinel.md
Comment on lines +1 to +4
## 2025-02-27 - [Path Traversal via Manual Path Normalization]
**Vulnerability:** In `crates/flow/src/incremental/extractors/typescript.rs`, manual path normalization for unresolved module paths naively popped components from the path stack when encountering `ParentDir` (`../`). This allowed popping the `RootDir` or `Prefix`, converting an absolute path into a relative one, or misinterpreting repeated `../` sequences, leading to potential path traversal vulnerabilities.
**Learning:** `std::path::Component::ParentDir` resolution in Rust requires careful state management. Simply using `components.pop()` fails to account for boundary conditions (like `RootDir` or empty stacks) which are crucial for maintaining the secure scope of file resolutions.
**Prevention:** Always use the robust component popping pattern: When encountering `ParentDir`, check if the last component in the stack is also `ParentDir`. If it is, or if the stack is empty, push `ParentDir`. Only pop the stack if the last component is a `Normal` directory, and never pop `RootDir` or `Prefix`.
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.

2 participants