ruvnet/RuView · error · anyhow::Error

refusing to use data dir with `..` traversal component: {raw

Error message

refusing to use data dir with `..` traversal component: {raw}

What it means

`sanitize_data_path` is the explicit path-traversal guard applied to every user-supplied `--data-dir` before a `TrainingSession` is created: it walks the path's components and refuses the value outright if any component is `..` (ParentDir). This is an intentional security refusal for CLI/API input, not an incidental failure, and the message says so.

Source

Thrown at v2/crates/wifi-densepose-pointcloud/src/training.rs:24

//! 2. **CSI occupancy training**: capture CSI with known occupancy ground truth →
//!    train the tomography weights for this room geometry
//! 3. **Brain integration**: store spatial observations as brain memories for
//!    DPO training — "this depth estimate was correct" vs "this was wrong"

use crate::fusion::OccupancyVolume;
use anyhow::{anyhow, Result};
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};

/// Reject a user-supplied path that contains `..` components (path traversal
/// attempt) and return a normalised [`PathBuf`]. We only reject `..`; other
/// components (including relative prefixes and `~`) are accepted verbatim —
/// the caller is responsible for tilde expansion if needed.
pub fn sanitize_data_path(raw: &str) -> Result<PathBuf> {
    let p = PathBuf::from(raw);
    for comp in p.components() {
        if matches!(comp, std::path::Component::ParentDir) {
            return Err(anyhow!(
                "refusing to use data dir with `..` traversal component: {raw}"
            ));
        }
    }
    Ok(p)
}

/// Ensure `child` (after joining to `base`) stays inside the canonicalised
/// `base` directory. Returns the canonical child path on success. Used by
/// every filesystem write site in this module to prevent path-traversal
/// through user-supplied names.
fn safe_join(base: &Path, child: &str) -> Result<PathBuf> {
    // Reject absolute children and any `..` components up front.
    let child_path = Path::new(child);
    if child_path.is_absolute() {
        return Err(anyhow!("child path must be relative: {child}"));
    }
    for comp in child_path.components() {

View on GitHub (pinned to 4685618388)

Solutions

  1. Resolve the path first (`realpath -m ../shared`) and pass the resulting absolute path, which contains no `..` components.
  2. If a parent directory is genuinely intended, name it explicitly by its canonical absolute location.
  3. Audit callers that build the string from untrusted input before it reaches `TrainingSession::new`.

Example fix

# before
ruview-train --data-dir ../runs/session7
# after
ruview-train --data-dir /home/op/runs/session7
Defensive patterns

Strategy: validation

Validate before calling

fn contains_parent_dir(raw: &str) -> bool {
    std::path::Path::new(raw)
        .components()
        .any(|c| matches!(c, std::path::Component::ParentDir))
}

fn sanitized(raw: &str) -> Option<std::path::PathBuf> {
    (!contains_parent_dir(raw)).then(|| std::path::PathBuf::from(raw))
}

Type guard

fn is_sanitizable_data_dir(raw: &str) -> bool {
    !std::path::Path::new(raw)
        .components()
        .any(|c| matches!(c, std::path::Component::ParentDir))
}

Prevention

When it happens

Trigger: `--data-dir ../outside`; `--data-dir captures/../../tmp/evil`; any caller that concatenates untrusted fragments into the data dir string and happens to embed `..`.

Common situations: Automation passing `$HOME/../shared`; an HTTP API reusing this crate whose clients send relative parent references; config values authored on a different machine with `..` shortcuts.

Related errors


AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16). Data as JSON: /api/errors/73df06cdb09c8743. Report an issue: GitHub.