Expand description
Β§strict-path
Secure path handling for untrusted input. Prevents directory traversal, symlink escapes,
and 19+ real-world CVE attack patterns.
If a StrictPath value exists, the path is proven to be inside its boundary β by construction,
not by string checks.
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, config loading, shared system resources, file uploads to shared storage (admin panels, CMS)
- 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 file uploads (SaaS per-user storage), 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 (with
proc-canonicalize for Linux container realpath support),
this crate protects against:
- CVE-2025-8088 (NTFS ADS path traversal)
- CVE-2022-21658 (TOCTOU attacks)
- CVE-2019-9855, CVE-2020-12279, CVE-2017-17793 (Windows 8.3 short names)
- Path traversal, symlink attacks, Unicode normalization bypasses, null byte injection, race conditions
Trade-off: Security is prioritized above performance. This crate verifies paths on disk and follows symlinks for validation. If your use case doesnβt involve symlinks and you need maximum performance, a lexical-only solution may be a better fit.
Scope: Validation happens at join-time (canonicalization + boundary check). Filesystem changes between validation and I/O are outside scope (TOCTOU) β the same limitation as SQL prepared statements, which prevent injection but donβt protect against concurrent schema changes.
β 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 Context (Full) β Concise, copy-pastable reference optimized for AI assistants
- LLM Context (Context7) β Context7-style usage guide for AI agents
- 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::strict_path::StrictOpenOptions;pub use path::strict_path::StrictReadDir;pub use validator::path_boundary::BoundaryReadDir;pub use path::virtual_path::VirtualPath;pub use path::virtual_path::VirtualReadDir;pub use validator::virtual_root::VirtualRoot;pub use validator::virtual_root::VirtualRootReadDir;
ModulesΒ§
- error
- 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.