zeroclaw-labs/zeroclaw · error · anyhow::Error

runtime.wasm.tools_dir must not contain '..' path traversal

Error message

runtime.wasm.tools_dir must not contain '..' path traversal

What it means

Final WASM config guard: tools_dir must not contain '..' because it is joined onto the workspace root to resolve module paths (tools_dir()), and '..' segments would let the resolved path escape the workspace sandbox. This is a path-traversal containment check on untrusted config input — even a module name cannot then reach outside the workspace tree.

Source

Thrown at crates/zeroclaw-runtime/src/platform/wasm.rs:81

    }

    /// Validate the WASM config for common misconfigurations.
    pub fn validate_config(&self) -> Result<()> {
        if self.config.memory_limit_mb == 0 {
            bail!("runtime.wasm.memory_limit_mb must be > 0");
        }
        if self.config.memory_limit_mb > 4096 {
            bail!(
                "runtime.wasm.memory_limit_mb of {} exceeds the 4 GB safety limit for 32-bit WASM",
                self.config.memory_limit_mb
            );
        }
        if self.config.tools_dir.is_empty() {
            bail!("runtime.wasm.tools_dir cannot be empty");
        }
        // Verify tools directory doesn't escape workspace
        if self.config.tools_dir.contains("..") {
            bail!("runtime.wasm.tools_dir must not contain '..' path traversal");
        }
        Ok(())
    }

    /// Resolve the absolute path to the WASM tools directory.
    pub fn tools_dir(&self, workspace_dir: &Path) -> PathBuf {
        workspace_dir.join(&self.config.tools_dir)
    }

    /// Build capabilities from config defaults.
    pub fn default_capabilities(&self) -> WasmCapabilities {
        WasmCapabilities {
            read_workspace: self.config.allow_workspace_read,
            write_workspace: self.config.allow_workspace_write,
            allowed_hosts: self.config.allowed_hosts.clone(),
            fuel_override: 0,
            memory_override_mb: 0,
        }

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Use a directory inside the workspace: tools_dir = "tools/wasm"
  2. To share modules between workspaces, copy or symlink the directory inside each workspace (a symlink inside is still contained) and keep the config traversal-free
  3. Move the artifact build output into the workspace (adjust your build to emit into <workspace>/tools/wasm)
  4. Never encode '..' in the config; the check is a substring match, so even a legitimate-looking '../x' is refused

Example fix

# before
[runtime.wasm]
tools_dir = "../shared/wasm"

# after
# ln -s /srv/shared/wasm <workspace>/tools/wasm
[runtime.wasm]
tools_dir = "tools/wasm"
Defensive patterns

Strategy: validation

Validate before calling

if cfg.tools_dir.contains("..") {
    return Err("tools_dir must stay inside the workspace".into());
// stronger: canonicalize and assert the resolved path starts with the workspace root
}
let resolved = workspace_dir.join(&cfg.tools_dir).canonicalize()?;
if !resolved.starts_with(workspace_dir.canonicalize()?) {
    return Err("tools_dir escapes workspace".into());
}

Try / catch

if let Err(e) = platform.validate_config() {
    if e.to_string().contains("path traversal") {
        // security guard: reconfigure to an in-workspace directory; never strip the check
    }
}

Prevention

When it happens

Trigger: Setting tools_dir = "../shared/wasm" to point at a directory outside the workspace; ".." style leftovers from templating; configs written by users assuming absolute-ish traversal is allowed.

Common situations: Trying to share one tools directory between multiple workspaces via traversal; monorepo layouts where the wasm artifacts live above the agent workspace; porting configs from setups that permitted absolute paths.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/5f79fe72b04089d3. Report an issue: GitHub.