Expand description
Β§strict-path
Handle paths from external or unknown sources securely. Uses Rustβs type system to mathematically prove paths stay within defined boundariesβno escapes in any shape or form, symlinks included. API is minimal, restrictive, and explicit to prevent human and LLM API misuse.
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.
β 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
- 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.