Skip to content

fix(restore): prevent path traversal in LocalDestination - #590

Open
Huge wants to merge 1 commit into
rustic-rs:mainfrom
Huge:fix/local-destination-path-traversal
Open

Huge wants to merge 1 commit into
rustic-rs:mainfrom
Huge:fix/local-destination-path-traversal

Conversation

@Huge

@Huge Huge commented Oct 6, 2026

Copy link
Copy Markdown

Problem

LocalDestination::path in crates/core/src/backend/local_destination.rs joins relative item paths via self.path.join(item) without sanitization (and create_dir was previously doing self.path.join(item) directly).

In Rust's Path::join, if item contains path traversal components (..) or is an absolute path (leading / or Windows drive prefix), the resulting path escapes self.path. When restoring an archive or snapshot containing crafted or malformed tree node paths, this allows writing, directory creation, truncating, hardlinking, and metadata modifications outside the intended destination directory.

Fix

  • Added LocalDestinationErrorKind::ItemPathEscapesDestination(PathBuf).
  • Updated LocalDestination::path to return LocalDestinationResult<PathBuf> and inspect path components fail-closed: rejects Prefix, RootDir, and ParentDir components.
  • Updated create_dir to route through self.path(item)? instead of unchecked self.path.join(item).
  • Updated callers across LocalDestination and restore.rs to propagate errors cleanly.

Tests

  • Added test_path_sanitization: verifies valid relative paths succeed, while ../escaped, ../../etc/passwd, a/../../b, and /absolute/path return ItemPathEscapesDestination.
  • Added test_operations_reject_traversal: verifies create_dir, write_at, read_at, and get_matching_file reject traversal paths without filesystem writes outside destination.
  • Verified existing restore integration test (cargo test -p rustic_core --test integration restore) passes.

Disclaimer: Found the issue by test-driving an LM-powered vulnerability scanner I work on heavily.

Sanitize and validate relative item paths in LocalDestination::path
to prevent directory traversal attacks when restoring snapshots.

Previously, LocalDestination::path concatenated item paths via
self.path.join(item) (or self.path.join directly in create_dir).
If a snapshot or archive contained absolute paths or traversal
components (such as '..' or leading '/'), the resolved path escaped
the destination root directory, allowing arbitrary file creation,
truncation, permission modifications, or writes outside the intended
restore location.

Changes:
- Added LocalDestinationErrorKind::ItemPathEscapesDestination(PathBuf).
- Validated item components in LocalDestination::path fail-closed
  against Prefix, RootDir, and ParentDir components.
- Hardened create_dir, write_at, hard_link, set_length,
  metadata helpers, and restore.rs call sites.
- Added unit tests for path sanitization and traversal rejection.

Reported-by: BS.ehlas.cz
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.

1 participant