Executive brief
CodeWhale's image_analyze tool, used to analyze images in AI workflows, fails to properly restrict file access to the workspace boundary. An attacker can create a symlink with an image extension name pointing to sensitive files outside the workspace. The tool automatically processes this symlink without user approval and sends the file contents base64-encoded to the configured vision API endpoint, exposing arbitrary file bytes to the vision provider and any network intermediary.
Technical details
The vulnerability is a path traversal via symlink in the image_analyze tool (crates/tui/src/vision/tools.rs). The tool performs a lexical check to reject absolute paths and parent-dir components but does not canonicalize the path, so it fails to detect symlinks that bypass the checks. When a symlink like "workspace/screenshot.png → /etc/passwd" is provided, the lexical check passes (components are [Normal("screenshot.png")]), but the subsequent tokio::fs::read() call follows the symlink to the target file. The file contents are then base64-encoded and embedded in a chat-completion request POSTed to the vision endpoint with the user's authorization token. The tool declares ReadOnly capability and relies on the trait default approval_requirement(), which resolves to Auto, allowing the model to invoke it without user prompts. Other file-reading tools in the same codebase use the central ToolContext::resolve_path() method, which canonicalizes paths and properly rejects symlinks escaping the workspace. The fix is a one-line change to use resolve_path() instead of context.workspace.join(). Patched in version 0.8.64.
Affected products
- CodeWhale codewhale >=0.8.41, <0.8.64
- CodeWhale codewhale-tui >=0.8.41, <0.8.64
- CodeWhale deepseek-tui >=0.8.32, <=0.8.41
Timeline
- 2026-09-04: disclosed: Vulnerability advisory published
- 2026-07-16: patched: Fix released in version 0.8.64 (commit 26de44a8bd5051f8f944ea60b2c37ae1d2b7d25e)
- 2026-05-12: other: Earlier incomplete fix (commit 2326220) attempted to address Windows paths but missed the fundamental symlink canonicalization issue