Expand description
Β§strict-path
Strictly enforce path boundaries to prevent directory traversal attacks.
This crate performs full normalization/canonicalization and boundary enforcement with:
- Safe symlink/junction handling (including cycle detection)
- Windows-specific quirks (8.3 short names, UNC and verbatim prefixes, ADS)
- Robust Unicode normalization and mixed-separator handling across platforms
- Canonicalized path proofs encoded in the type system
If a StrictPath<Marker> value exists, it is already proven to be inside its
designated boundary by construction β not by best-effort string checks.
π Complete Guide & Examples | π API Reference
Β§Quick Start
// GET /download?file=report.pdf
let user_input = request.get("file").unwrap(); // Untrusted: "report.pdf" or "../../etc/passwd"
let untrusted_user_input = user_input.to_string();
let file: StrictPath = StrictPath::with_boundary(temp.path())?
.strict_join(&untrusted_user_input)?; // Validates untrusted input - attack blocked!
let contents = file.read()?; // Built-in safe I/OΒ§Core Types
StrictPathβ The fundamental security primitive. EveryStrictPathis mathematically proven to be within its designated boundary via canonicalization and type-level guarantees.PathBoundaryβ Creates and validatesStrictPathinstances from external input.VirtualPath(featurevirtual-path) β ExtendsStrictPathwith user-friendly virtual root semantics (treating the boundary as β/β).VirtualRoot(featurevirtual-path) β CreatesVirtualPathinstances with containment semantics.
β Read the security methodology
Β§Which Type Should I Use?
Path/PathBuf (std) β When the path comes from a safe source within your control, not external input.
StrictPath β When you want to restrict paths to a specific boundary and error if they escape.
- Use for: Archive extraction, file uploads, config loading, shared system resources
- Behavior: Returns
Err(PathEscapesBoundary)on escape attempts (detect attacks) - Coverage: 90% of use cases
VirtualPath (feature virtual-path) β When you want to provide path freedom under isolation.
- Use for: Multi-tenant systems, malware sandboxes, security research, per-user filesystem views
- Behavior: Silently clamps/redirects escapes within virtual boundary (contain behavior)
- Coverage: 10% of use cases
β Read the detailed comparison
Β§Type-System Guarantees
Use marker types to encode policy directly in your APIs:
struct PublicAssets;
struct UserUploads;
let assets = PathBoundary::<PublicAssets>::try_new("./assets")?;
let uploads = PathBoundary::<UserUploads>::try_new("./uploads")?;
// User input from request parameters, form data, database, etc.
let requested_css = "style.css"; // From request: /static/style.css
let uploaded_avatar = "avatar.jpg"; // From form: <input type="file">
let css: StrictPath<PublicAssets> = assets.strict_join(requested_css)?;
let avatar: StrictPath<UserUploads> = uploads.strict_join(uploaded_avatar)?;
fn serve_public_asset(file: &StrictPath<PublicAssets>) { /* ... */ }
serve_public_asset(&css); // β
OK
// serve_public_asset(&avatar); // β Compile error (wrong marker)Β§Security Foundation
Built on soft-canonicalize, this crate protects against:
- CVE-2025-8088 (NTFS ADS path traversal)
- CVE-2022-21658 (TOCTOU attacks)
- CVE-2019-9855, CVE-2020-12279 (Windows 8.3 short names)
- Path traversal, symlink attacks, Unicode normalization bypasses, race conditions
β Read attack surface analysis
Β§Interop with External APIs
Use .interop_path() to pass paths to external APIs expecting AsRef<Path>:
let restriction: PathBoundary = PathBoundary::try_new_create("./safe")?;
// User input from CLI args, API request, config file, etc.
let user_input = "file.txt";
let jp = restriction.strict_join(user_input)?;
// β
Preferred: borrow as &OsStr (implements AsRef<Path>)
external_api(jp.interop_path());
// Escape hatches (use sparingly):
let owned: std::path::PathBuf = jp.clone().unstrict();β Read the anti-patterns guide
Β§Critical Anti-Patterns
- NEVER wrap
.interop_path()inPath::new()orPathBuf::from()β defeats all security - NEVER use std path operations on untrusted input β use
.strict_join(), notPath::new().join() - Use
.interop_path()directly for external APIs β itβs alreadyAsRef<Path>, no wrapping needed - Use proper display methods β
.strictpath_display()not.interop_path().to_string_lossy()
Note: .interop_path() returns &OsStr (which is AsRef<Path>). After .unstrict() (explicit escape hatch), you own a PathBuf and can do whatever you need.
β See full anti-patterns list
Β§Feature Flags
virtual-pathβ EnablesVirtualRoot/VirtualPathfor containment scenariosjunctions(Windows) β Built-in NTFS junction helpers for strict/virtual paths
Β§Ecosystem Integration
Use ecosystem crates directly with PathBoundary for maximum flexibility:
tempfileβ RAII temporary directories viatempfile::tempdir()βPathBoundary::try_new()dirsβ OS standard directories viadirs::config_dir()βPathBoundary::try_new_create()app-pathβ Portable app paths viaAppPath::with("subdir")βPathBoundary::try_new_create()serdeβPathBoundary/VirtualRootimplementFromStrfor automatic deserialization
β See Ecosystem Integration Guide
β Read the getting started guide
Β§Additional Resources
- LLM API Reference β Concise, copy-pastable reference optimized for AI assistants
- Complete Guide β Comprehensive documentation with examples
- API Reference β Full type and method documentation
- Repository β Source code and issue tracker
Re-exportsΒ§
pub use error::StrictPathError;pub use path::strict_path::StrictPath;pub use validator::path_boundary::PathBoundary;pub use path::virtual_path::VirtualPath;pub use validator::virtual_root::VirtualRoot;
ModulesΒ§
- error
- SUMMARY: Define error types and helpers for boundary creation and strict/virtual path validation.
- path
- validator
Type AliasesΒ§
- Result
- Result type alias for this crateβs operations.