# strict-path
[](https://crates.io/crates/strict-path)
[](https://docs.rs/strict-path)
[](https://github.com/DK26/strict-path-rs#license)
[](https://github.com/DK26/strict-path-rs/actions/workflows/ci.yml)
[](https://github.com/DK26/strict-path-rs/actions/workflows/audit.yml)
[](https://github.com/DK26/strict-path-rs/actions/workflows/kani.yml)
[](https://github.com/DK26/strict-path-rs/blob/main/strict-path/src/path/tests/cve_2025_11001.rs)
[](https://github.com/DK26/strict-path-rs)
**Handle paths from external or unknown sources securely.** `strict-path` defends against 19+ real-world CVEs including symlinks, Windows 8.3 short names, and encoding tricks and exploits.
> **Analogy:** `strict-path` is to paths what prepared statements are to SQL.
## β‘ **Get Secure in 30 Seconds**
```toml
[dependencies]
strict-path = "0.1"
```
```rust
use strict_path::StrictPath;
// GET /download?file=report.pdf
let untrusted_user_input = request.query_param("file").to_string(); // Untrusted: "report.pdf" or "../../etc/passwd"
let file = StrictPath::with_boundary("/var/app/downloads")?
.strict_join(&untrusted_user_input)?; // Validates untrusted input - attack blocked!
let contents = file.read()?; // Safe built-in I/O
send_response(contents);
```
> **Note:** Our doc comments and [LLM_CONTEXT_FULL.md](https://github.com/DK26/strict-path-rs/blob/main/LLM_CONTEXT_FULL.md) are designed for LLMs with function callingβenabling AI agents to use this crate safely and correctly for file and path operations.
>
> ### π€ LLM agent prompt (copy/paste)
>
> ```
> Fetch and follow this reference (single source of truth):
> https://github.com/DK26/strict-path-rs/blob/main/LLM_CONTEXT_FULL.md
> ```
>
> #### Context7 Style
>
> ```
> Fetch and follow this reference (single source of truth):
> https://github.com/DK26/strict-path-rs/blob/main/LLM_CONTEXT.md
> ```
> π **New to strict-path?** Start with the **[Tutorial: Chapter 1 - The Basic Promise β](https://dk26.github.io/strict-path-rs/tutorial/chapter1_basic_promise.html)**
## π‘οΈ **Complete Path Security**
**strict-path handles edge cases you'd never think to check:**
1. **π§ [`soft-canonicalize`](https://github.com/DK26/soft-canonicalize-rs) foundation**: Battle-tested against 19+ real-world path CVE scenarios
2. **π Full canonicalization**: Resolves symlinks, junctions, `.`/`..` components, handles race conditions
3. **π« Advanced attacks**: Catches Windows 8.3 short names (`PROGRA~1`), UNC paths, NTFS ADS, encoding tricks
4. **π Compile-time proof**: Rust's type system enforces path boundaries
5. **ποΈ Explicit operations**: Method names like `strict_join()` make security visible in code review
6. **π‘οΈ Built-in I/O**: Complete filesystem API
7. **π€ LLM-aware**: Built for untrusted AI-generated code and modern threat models
8. **β‘ Dual modes**: **PathBoundary** (detection & rejection) or **VirtualRoot** (clamping & containing)
**Real attacks we handle automatically:**
- Path traversal (`../../../etc/passwd`)
- Symlink/junction escapes
- Windows 8.3 short names (`PROGRA~1` β `Program Files`)
- NTFS Alternate Data Streams (`file.txt:hidden:$DATA`)
- Unicode normalization bypasses (`..β..βetcβpasswd`)
- Null byte injection (`file.txt\x00.pdf`)
- Mixed separators (`../\../etc/passwd`)
- UNC path tricks (`\\?\C:\..\..\etc\passwd`)
- Archive attacks (Zip slip - CVE-2018-1000178)
- Race conditions (TOCTOU - CVE-2022-21658)
**Recently Addressed CVEs:**
- **CVE-2025-8088** (WinRAR): NTFS Alternate Data Stream traversal
- **CVE-2022-21658**: Race condition protection (TOCTOU)
- **CVE-2019-9855, CVE-2020-12279, CVE-2017-17793**: Windows 8.3 short names
**What This Is NOT:**
- β **Not just string checking** (handles symlinks, Windows quirks)
- β **Not a kernel based sandbox** (path-level security only)
> π **[Read our complete security methodology β](https://dk26.github.io/strict-path-rs/security_methodology.html)** | π **[Built-in I/O Methods β](https://dk26.github.io/strict-path-rs/best_practices.html#builtin-io-operations)**
## π― **StrictPath vs VirtualPath: When to Use What**
### 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.
- **VirtualPath**: When you want to provide path freedom under isolation.
**Choose StrictPath (90% of cases):**
- Archive extraction, config loading
- File uploads to shared storage (admin panels, CMS assets, single-tenant apps)
- LLM/AI agent file operations
- Shared system resources (logs, cache, assets)
- **Any case where escaping a path boundary, is considered malicious**
**Choose VirtualPath (10% of cases):**
- Multi-tenant file uploads (SaaS per-user storage, isolated user directories)
- Multi-tenant isolation (per-user filesystem views)
- Malware analysis sandboxes
- Container-like plugins
- **Any case where you would like to allow freedom of operations under complete isolation**
> π **[Complete Decision Matrix β](https://dk26.github.io/strict-path-rs/best_practices.html)** | π **[More Examples β](https://dk26.github.io/strict-path-rs/examples.html)**
> **API Philosophy:** Minimal, restrictive, and explicitβdesigned to prevent and easily detect both human and LLM agent API misuse. Security is prioritized above performance; if your use case doesn't involve symlinks and you need to squeeze every bit of performance, a lexical-only solution may be a better fit. `strict-path` accesses the disk to validate and secure paths, by resolving all its components. This predicts correctly where a path would end-up leading to on a disk filesystem by simulating disk access. This method ignores anything a hacker could put as input path string, since we validate only against where the file being accessed from or written to, would end up being.
---
## π **More Real-World Examples**
### Archive Extraction (Zip Slip Prevention)
`PathBoundary` is a special type that represents a boundary for paths. It is optional, and could be used to express parts in our code where we expect a path to represent a boundary path:
```rust
use strict_path::PathBoundary;
// Prevents CVE-2018-1000178 (Zip Slip) automatically (https://snyk.io/research/zip-slip-vulnerability)
fn extract_archive(
extraction_dir: PathBoundary,
archive_entries: impl IntoIterator<Item=(String, Vec<u8>)>) -> std::io::Result<()> {
for (entry_path, data) in archive_entries {
// Malicious paths like "../../../etc/passwd" β Err(PathEscapesBoundary)
let safe_file = extraction_dir.strict_join(&entry_path)?;
safe_file.create_parent_dir_all()?;
safe_file.write(&data)?;
}
Ok(())
}
```
> The equivalent `PathBoundary` for `VirtualPath` type is the `VirtualRoot` type.
### Multi-Tenant Isolation
```rust
use strict_path::VirtualRoot;
// No path-traversal or symlinks, could escape a tenant.
// Everything is clamped to the virtual root, including symlink resolutions.
fn handle_file_request(tenant_id: &str, requested_path: &str) -> std::io::Result<Vec<u8>> {
let tenant_root = VirtualRoot::try_new_create(format!("./tenants/{tenant_id}"))?;
// "../../other_tenant/secrets.txt" β clamped to "/other_tenant/secrets.txt" in THIS tenant
let user_file = tenant_root.virtual_join(requested_path)?;
user_file.read()
}
```
---
## π§ **Compile-Time Safety with Markers**
`StrictPath<Marker>` enables **domain separation and authorization** at compile time:
```rust
struct UserFiles;
struct SystemFiles;
fn process_user(f: &StrictPath<UserFiles>) -> Vec<u8> { f.read().unwrap() }
let user_boundary = PathBoundary::<UserFiles>::try_new_create("./data/users")?;
let sys_boundary = PathBoundary::<SystemFiles>::try_new_create("./system")?;
let user_input = get_filename_from_request();
let user_file = user_boundary.strict_join(user_input)?;
process_user(&user_file); // β
OK - correct marker type
let sys_file = sys_boundary.strict_join("config.toml")?;
// process_user(&sys_file); // β Compile error - wrong marker type!
```
> π **[Complete Marker Tutorial β](https://dk26.github.io/strict-path-rs/tutorial/chapter3_markers.html)** - Authorization patterns, permission matrices, `change_marker()` usage
---
### vs `soft-canonicalize`
**Compared with manual soft-canonicalize path validations:**
- `soft-canonicalize` = low-level path resolution engine (returns `PathBuf`)
- `strict-path` = high-level security API (returns `StrictPath<Marker>` with compile-time guarantees: fit for LLM era)
> π **[Security Methodology β](https://dk26.github.io/strict-path-rs/security_methodology.html)** | π **[Anti-Patterns Guide β](https://dk26.github.io/strict-path-rs/anti_patterns.html)**
---
## π **Ecosystem Integration**
Compose with standard Rust crates for complete solutions:
| Integration | Purpose | Guide |
| ------------ | ----------------------- | ------------------------------------------------------------------------------------------- |
| **tempfile** | Secure temp directories | [Guide](https://dk26.github.io/strict-path-rs/ecosystem_integration.html#tempfile) |
| **dirs** | OS standard directories | [Guide](https://dk26.github.io/strict-path-rs/os_directories.html) |
| **app-path** | Application directories | [Guide](https://dk26.github.io/strict-path-rs/ecosystem_integration.html#app-path) |
| **serde** | Safe deserialization | [Guide](https://dk26.github.io/strict-path-rs/ecosystem_integration.html#serde-and-fromstr) |
| **Axum** | Web server extractors | [Tutorial](https://dk26.github.io/strict-path-rs/axum_tutorial/overview.html) |
| **Archives** | ZIP/TAR extraction | [Guide](https://dk26.github.io/strict-path-rs/examples/archive_extraction.html) |
> π **[Complete Integration Guide β](https://dk26.github.io/strict-path-rs/ecosystem_integration.html)**
---
## π **Learn More**
- π **[API Documentation](https://docs.rs/strict-path)** - Complete API reference
- π **[User Guide](https://dk26.github.io/strict-path-rs/)** - Tutorials and patterns
- [Best Practices](https://dk26.github.io/strict-path-rs/best_practices.html) - Detailed decision matrix
- [Anti-Patterns](https://dk26.github.io/strict-path-rs/anti_patterns.html) - Common mistakes
- [Examples](https://dk26.github.io/strict-path-rs/examples.html) - Copy-paste scenarios
- π§ **[LLM_CONTEXT_FULL.md](LLM_CONTEXT_FULL.md)** - Full API reference for AI agents
- π **[LLM_CONTEXT.md](LLM_CONTEXT.md)** - Context7-style usage guide for AI agents
- π οΈ **[`soft-canonicalize`](https://github.com/DK26/soft-canonicalize-rs)** - Path resolution engine
π **[Complete Guide & Examples](https://dk26.github.io/strict-path-rs/)** | π **[API Docs](https://docs.rs/strict-path)** | π§ **[Choosing Canonicalized vs Lexical Solution](https://dk26.github.io/strict-path-rs/ergonomics/choosing_canonicalized_vs_lexical_solution.html)**
---
## π **License**
MIT OR Apache-2.0