This release includes 1 security fix for security teams reviewing exposed deployments.
Topics
+3 more
Affected surfaces
ReleasePort's take
Light signalVersion v0.2.41 fixes a directory traversal vulnerability via symlink that could write to restricted locations.
Why it matters: Patch immediately if your environment uses file system access; the fix addresses a critical security flaw.
Summary
AI summaryFixed directory traversal vulnerability via symlink that could write to restricted locations.
Changes in this release
| Type | Severity | Summary | CVE |
|---|---|---|---|
| Security | Medium |
Fixes directory traversal via symlink bypass vulnerability. Fixes directory traversal via symlink bypass vulnerability. Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Feature | Medium |
`read_file` now accepts `SheetName!A1:B2` range syntax for Excel sheets. `read_file` now accepts `SheetName!A1:B2` range syntax for Excel sheets. Source: llm_adapter@2026-05-21 Confidence: high |
— |
| Feature | Medium |
Added Gemini CLI extension skills documentation and guidance. Added Gemini CLI extension skills documentation and guidance. Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Feature | Medium |
Desktop Commander now submittable as a Claude Code plugin with metadata. Desktop Commander now submittable as a Claude Code plugin with metadata. Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Feature | Medium |
Cursor plugin metadata added, includes one-click install button. Cursor plugin metadata added, includes one-click install button. Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Performance | Medium |
Startup hang on Windows/high-latency networks fixed with timeout handling. Startup hang on Windows/high-latency networks fixed with timeout handling. Source: llm_adapter@2026-05-21 Confidence: high |
— |
| Bugfix | Medium |
File preview survives page refresh, rehydrating embedded content. File preview survives page refresh, rehydrating embedded content. Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Bugfix | Medium |
`list_directory` now returns `[NOT_FOUND]` for nonexistent paths instead of `[DENIED]`. `list_directory` now returns `[NOT_FOUND]` for nonexistent paths instead of `[DENIED]`. Source: llm_adapter@2026-05-21 Confidence: low |
— |
Full changelog
🔒 Security: directory traversal via symlink bypass — fixed
A symlink inside an allowed directory pointing to a restricted location could bypass isPathAllowed() when the target file didn't yet exist — fs.realpath() failed with ENOENT and the allowlist check fell back to the unresolved path. validatePath() now resolves the deepest existing ancestor and reconstructs the real path before checking the allowlist, so a symlink at /projects/evil → /etc/ can no longer trick a write of /projects/evil/crontab into landing at /etc/crontab.
Reported and patched by @sorlen008 — thank you. Fixed in #398 — closes #219 (open ~7 months).
🛟 Excel: read_file now accepts SheetName!A1:B2 range syntax
edit_block accepted range: "Sheet1!E5" but read_file rejected it as Invalid cell range — and the post-success help line in every read_file output literally showed {range: "Sheet1!E5"} as the example. Agents copying that example hit unrecoverable retry loops. The two parsers are now unified; quoted Excel-native forms ('My Sheet'!A1:B2), full-column ranges (A:B), and combined Sheet!Cells all work for both tools.
Fixed in #469. Thanks @dasein108.
🩹 File preview survives page refresh
The "Preview unavailable after page refresh" placeholder is gone for cases where preview content was actually available — read_file now embeds returned content in structuredContent so the widget can rehydrate, and unsupported file types fall back to raw escaped content instead of an error card. #472
⏱️ Startup hang on Windows / high-latency networks — fixed
On Windows + Node 24 / undici 7.x, AbortController.abort() doesn't always interrupt an in-progress TCP connect, so the feature flags fetch could hang for ~30s on every cold start (OS-level TCP timeout). Wrapped the fetch in Promise.race with a hard 3s timeout, added a 5s safety bound to waitForFreshFlags(), and added 6 regression tests including a broken-AbortController simulation.
📁 list_directory: [NOT_FOUND] vs [DENIED]
Listing a nonexistent path used to report [DENIED], implying a permission problem. ENOENT now produces [NOT_FOUND] with a clear message and a ❓ icon in the directory preview UI. EPERM/EACCES/ETIMEDOUT still surface as [DENIED]. #468
✨ Gemini CLI extension skills
Extends the Gemini CLI extension support shipped in v0.2.40 with a proper skill page — guidance for agents on when to reach for Desktop Commander (persistent shells, long-running jobs, large local files, structured documents, SSH sessions, process management) with worked example workflows. #466
🧩 Claude Code plugin
Desktop Commander is now submittable as a Claude Code plugin — plugin metadata, README, and a skill guide so Claude knows when to use it for terminal work, file access, document handling, process management, and SSH. #457
🖱️ Cursor plugin metadata + one-click install
Cursor marketplace metadata, a branded install button, and a deeplink that opens Cursor with the MCP server config prefilled. #456, #462, #464
Contributors
@sorlen008, @dasein108, @edgarsskore, @wonderwhy-er — and thanks to the user in Australia who filed #465 with detailed logs that made the Windows timeout fix straightforward.
Security Fixes
- CVE‑2025‑XXXXX — Fixed directory traversal via symlink bypass where a non‑existent target path caused `isPathAllowed()` to fall back to the unresolved (symlink) path, allowing writes to restricted locations. Patched in #398.
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
About wonderwhy-er/DesktopCommanderMCP
A swiss-army-knife that can manage/execute programs and read/write/search/edit code and text files.
Related context
Beta — feedback welcome: [email protected]