Expand description
A zero-dependency filesystem sandbox for Rust.
Restricts paths to a root directory, preventing traversal attacks while supporting files that don’t exist yet.
§Quick Start
For one-off validation, use the join function:
let safe_path = path_jail::join("/var/uploads", "user/file.txt")?;
std::fs::write(&safe_path, b"hello")?;For validating multiple paths, create a Jail and reuse it:
use path_jail::Jail;
let jail = Jail::new("/var/uploads")?;
let path1 = jail.join("report.pdf")?;
let path2 = jail.join("data.csv")?;§TOCTOU-Safe File Operations (guard API)
Enable the guard feature for kernel-enforced containment via
openat2(RESOLVE_BENEATH) on Linux 5.6+:
[dependencies]
path_jail = { version = "0.4", features = ["guard"] }use path_jail::guard::{FdJail, OpenOptions};
let jail = FdJail::new("/var/uploads")?;
let mut gf = jail.open("report.pdf", OpenOptions::new().read(true))?;
if gf.has_hard_links() {
// Enforce hard-link policy here
}
use std::io::Read;
let mut buf = Vec::new();
gf.read_to_end(&mut buf)?;§Type-Safe Paths
For compile-time guarantees, use JailedPath:
use path_jail::{Jail, JailedPath};
fn save_upload(path: JailedPath, data: &[u8]) -> std::io::Result<()> {
// path is guaranteed to be inside the jail
std::fs::write(&path, data)
}
let jail = Jail::new("/var/uploads")?;
let path = jail.join_typed("report.pdf")?;
save_upload(path, b"data")?;§Security
This crate blocks:
- Path traversal (
../../etc/passwd) - Symlink escapes (symlinks pointing outside the jail)
- Absolute path injection (
/etc/passwd) - Null byte injection (
file\x00.txt) - Broken symlinks (cannot verify target)
With guard: all of the above plus TOCTOU races, magic links
(/proc/self/fd), and intermediate directory attacks (Linux 5.6+).
See Jail and [guard::FdJail] for details.
Structs§
- Jail
- A filesystem sandbox that restricts paths to a root directory.
- Jailed
Path - A path verified to be inside a
Jail.
Enums§
- Jail
Error - Errors returned by path_jail operations.
Functions§
- join
- Validate a path in one shot.