{"record":{"id":"a54490fbbb3523b2","repo":"zeroclaw-labs/zeroclaw","slug":"slack-attachment-save-directory-escapes-workspace","errorCode":null,"errorMessage":"Slack attachment save directory escapes workspace: {}","messagePattern":"Slack attachment save directory escapes workspace: (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/slack.rs","lineNumber":3310,"sourceCode":"            anyhow::Error::msg(format!(\"invalid attachment filename: {file_name}\"))\n        })?;\n\n        tokio::fs::create_dir_all(workspace).await?;\n        let workspace_root = tokio::fs::canonicalize(workspace)\n            .await\n            .unwrap_or_else(|_| workspace.to_path_buf());\n\n        let save_dir = workspace.join(SLACK_ATTACHMENT_SAVE_SUBDIR);\n        tokio::fs::create_dir_all(&save_dir).await?;\n        let resolved_save_dir = tokio::fs::canonicalize(&save_dir).await.with_context(|| {\n            format!(\n                \"failed to resolve Slack attachment save directory: {}\",\n                save_dir.display()\n            )\n        })?;\n\n        if !resolved_save_dir.starts_with(&workspace_root) {\n            anyhow::bail!(\n                \"Slack attachment save directory escapes workspace: {}\",\n                resolved_save_dir.display()\n            );\n        }\n\n        Ok(resolved_save_dir.join(safe_name))\n    }\n\n    fn sanitize_attachment_filename(file_name: &str) -> Option<String> {\n        let basename = Path::new(file_name).file_name()?.to_str()?.trim();\n        if basename.is_empty() || basename == \".\" || basename == \"..\" {\n            return None;\n        }\n\n        let sanitized: String = basename\n            .replace(['/', '\\\\'], \"_\")\n            .chars()\n            .take(SLACK_ATTACHMENT_FILENAME_MAX_CHARS)","sourceCodeStart":3292,"sourceCodeEnd":3328,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/slack.rs#L3292-L3328","documentation":"Error \"Slack attachment save directory escapes workspace: {}\" thrown in zeroclaw-labs/zeroclaw.","triggerScenarios":"Thrown at crates/zeroclaw-channels/src/slack.rs:3310 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Configure the Slack attachment save directory inside the workspace; remove path traversal components from the configured path."],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}