#path-traversal #fs

path_ratchet

Prevent path traversal attacks at type level

5 unstable releases

0.3.2 Sep 16, 2025
0.3.1 Apr 6, 2025
0.3.0 Dec 9, 2023
0.2.0 Dec 6, 2023
0.1.0 Dec 4, 2023

#183 in Security

Download history 98/week @ 2025-10-08 150/week @ 2025-10-15 119/week @ 2025-10-22 131/week @ 2025-10-29 29/week @ 2025-11-05 65/week @ 2025-11-12 36/week @ 2025-11-19 23/week @ 2025-11-26 40/week @ 2025-12-03 34/week @ 2025-12-17 31/week @ 2025-12-31 37/week @ 2026-01-07 53/week @ 2026-01-14 8/week @ 2026-01-21

129 downloads per month

LGPL-3.0-only

24KB
315 lines

PathBuf::push allows any form of path traversal:

#
let user_input = "/etc/shadow";
let mut filename = PathBuf::from("/tmp");
filename.push(user_input);
assert_eq!(filename, PathBuf::from("/etc/shadow"));

Contrary <PathBuf as PushPathComponent>::push_component requires a path with only a single element.

use std::path::PathBuf;
use path_ratchet::prelude::*;

let user_input = "/etc/shadow";
let mut filename = PathBuf::from("/tmp");
filename.push_component(SingleComponentPath::new(user_input).unwrap());

Security

It is essential to check the path on the same platform it is used on. As an example the absolute windows path C:\path\to\file.txt will be interpreted as a simple file or directory name on an UNIX-system.

SingleComponentPath::new(r"C:\path\to\file.txt").unwrap();

Further path-ratchet is effective against classic path traversals where the path is an untrusted input in the threat model. In threat models where the attacker has access to the file system (e.g. can create symlinks), this approach isn't sufficent and should be complemented with sandboxing and/or a capability based approach (e.g. cap-std)

Features

  • serde

It is compatible with clap by default.


Path Ratchet

LGPL 3.0 License Crates.io Workflow Status crev reviews

Prevent path traversal attacks at type level.

use std::path::PathBuf;
use path_ratchet::prelude::*;

let user_input = "/etc/shadow";
let mut filename = PathBuf::from("/tmp");
filename.push_component(SingleComponentPath::new(user_input).unwrap());

Dependencies

~120KB