zed-industries/zed · error · anyhow::Error

path {path:?} escapes its parent

Error message

path {path:?} escapes its parent

What it means

The sandboxed path check in writeable_path_from_extension rejected a path: after lexically normalizing the candidate (extension work dir joined with the requested path), the result escapes the extension's work directory via '..' components or an absolute-path trick. This is a security guard preventing a wasm extension from writing outside its assigned directory.

Source

Thrown at crates/extension_host/src/wasm_host.rs:781

    }

    pub async fn writeable_path_from_extension(
        &self,
        id: &Arc<str>,
        path: &Path,
    ) -> Result<PathBuf> {
        let canonical_work_dir = self
            .fs
            .canonicalize(&self.work_dir)
            .await
            .with_context(|| format!("canonicalizing work dir {:?}", self.work_dir))?;
        let extension_work_dir = canonical_work_dir.join(id.as_ref());

        let absolute = if path.is_relative() {
            extension_work_dir.join(path)
        } else {
            path.to_path_buf()
        };

        let normalized = util::paths::normalize_lexically(&absolute)
            .map_err(|_| anyhow!("path {path:?} escapes its parent"))?;

        // Canonicalize the nearest existing ancestor to resolve any symlinks
        // in the on-disk portion of the path. Components beyond that ancestor
        // are re-appended, which lets this work for destinations that don't
        // exist yet (e.g. nested directories created by tar extraction).
        let mut existing = normalized.as_path();
        let mut tail_components = Vec::new();
        let canonical_prefix = loop {
            match self.fs.canonicalize(existing).await {
                Ok(canonical) => break canonical,
                Err(_) => {
                    if let Some(file_name) = existing.file_name() {
                        tail_components.push(file_name.to_owned());
                    }
                    existing = existing

View on GitHub (pinned to 5a9b9558db)

Solutions

  1. Fix the extension code to request paths relative to its own work dir without '..' traversal
  2. If a path outside the work dir is legitimately needed, use the host-provided API surfaces rather than raw fs writes
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at crates/extension_host/src/wasm_host.rs:772 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of zed-industries/zed@5a9b9558db (2026-08-20). Data as JSON: /api/errors/ace1831af5481b46. Report an issue: GitHub.