Skip to content

fix: reject unsafe torrent output paths#245

Open
artrixdotdev wants to merge 2 commits into
mainfrom
fix/harden-torrent-output-paths
Open

fix: reject unsafe torrent output paths#245
artrixdotdev wants to merge 2 commits into
mainfrom
fix/harden-torrent-output-paths

Conversation

@artrixdotdev

@artrixdotdev artrixdotdev commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Summary

  • Reject unsafe torrent metadata path segments before piece paths are joined to the output directory
  • Surface unsafe metadata paths through a typed TorrentError::UnsafeOutputPath
  • Cover single-file, multi-file, and actual write-path escape attempts

Fixes #234
Part of #221

Testing

  • cargo fmt --all --check
  • cargo nextest run -p libtortillas piece_manager
  • cargo nextest run --workspace --all-features
  • cargo clippy --workspace --all-targets --all-features -- -D warnings

Ignored network tests were not run because this change is limited to local torrent output path validation.

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of torrent file paths to reject unsafe names and path components.
    • Prevented torrents from writing output outside the intended destination when metadata includes absolute paths or directory traversal.
    • Ensured safe torrent paths are still mapped correctly for both single-file and multi-file torrents.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This PR adds a TorrentError::UnsafeOutputPath variant and a push_torrent_path_segment validation helper in piece_manager.rs, applying it to single-file and multi-file piece_to_paths construction to reject unsafe path components. Tests cover safe/unsafe path mapping and failed writes.

Changes

Torrent output path sanitization

Layer / File(s) Summary
Typed error and validation helper
crates/libtortillas/src/errors.rs, crates/libtortillas/src/pieces/piece_manager.rs
Adds TorrentError::UnsafeOutputPath { path: String } and a push_torrent_path_segment helper that rejects segments with separators or parent-directory traversal, using updated std imports.
piece_to_paths validation wiring
crates/libtortillas/src/pieces/piece_manager.rs
Replaces direct path pushes in single-file and multi-file branches of piece_to_paths with calls to push_torrent_path_segment.
Test coverage
crates/libtortillas/src/pieces/piece_manager.rs
Adds InfoFile import, a multi_file_info helper, and async tests validating rejection of unsafe single/multi-file paths, correct mapping of safe multi-file paths, and prevention of writes to unsafe output paths.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant PieceManager as piece_to_paths
  participant Validator as push_torrent_path_segment

  Caller->>PieceManager: piece_to_paths(piece_index)
  PieceManager->>Validator: validate name/path segment
  alt segment safe
    Validator-->>PieceManager: appended PathBuf
    PieceManager-->>Caller: relative output path
  else segment unsafe
    Validator-->>PieceManager: TorrentError::UnsafeOutputPath
    PieceManager-->>Caller: error
  end
Loading

Possibly related PRs

  • artrixdotdev/tortillas#151: Both PRs modify the piece mapping logic in piece_manager.rs, with this PR extending piece_to_paths (introduced in #151) with unsafe-path validation and error handling.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly matches the change: it describes rejecting unsafe torrent output paths.
Linked Issues check ✅ Passed The PR adds path validation, a typed unsafe-path error, and tests for single- and multi-file torrents, matching #234's core requirements.
Out of Scope Changes check ✅ Passed The added helper, error variant, and tests are all in-scope for hardening torrent output path sanitization.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/harden-torrent-output-paths

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
crates/libtortillas/src/pieces/piece_manager.rs (1)

21-43: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Reject Windows reserved names and trailing dot/space segments.
CON, NUL, COM1, LPT1, and names ending in . or space still pass as Component::Normal, but Windows treats them specially. Add a small check here so torrent metadata can't produce paths that behave differently on that platform.

🤖 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 `@crates/libtortillas/src/pieces/piece_manager.rs` around lines 21 - 43, The
safety check in push_torrent_path_segment still allows Windows-reserved names
and segments with trailing dot or space, which can behave specially on that
platform. Extend the existing is_safe_segment validation in this helper to
reject reserved device names like CON, NUL, COM1, and LPT1, and also reject any
segment whose last character is a dot or space before calling
path.push(segment).
🤖 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 `@crates/libtortillas/src/pieces/piece_manager.rs`:
- Around line 21-43: The safety check in push_torrent_path_segment still allows
Windows-reserved names and segments with trailing dot or space, which can behave
specially on that platform. Extend the existing is_safe_segment validation in
this helper to reject reserved device names like CON, NUL, COM1, and LPT1, and
also reject any segment whose last character is a dot or space before calling
path.push(segment).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e3d70405-607d-4062-bb89-54e6cee47bf4

📥 Commits

Reviewing files that changed from the base of the PR and between 7797155 and 6c65ab6.

📒 Files selected for processing (2)
  • crates/libtortillas/src/errors.rs
  • crates/libtortillas/src/pieces/piece_manager.rs

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.

Harden torrent output path sanitization

1 participant