@n0zer0d4y/vulcan-file-ops 1.1.6 → 1.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,36 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.1.7] - 2025-11-18
9
+
10
+ ### Security
11
+
12
+ - **CRITICAL**: Fixed command approval bypass vulnerability in `execute_shell` tool
13
+ - Previously, unapproved commands could execute if they didn't match dangerous patterns and `requiresApproval` was not set
14
+ - Now enforces strict whitelist: ALL commands must be in `--approved-commands` list to execute
15
+ - Affected commands that were incorrectly allowed: `dir`, `whoami`, `ipconfig`, `type`, `copy`, `move`, `ren`, `del`, `mkdir`, `rmdir`
16
+ - Added defense-in-depth: dangerous patterns now checked even on approved commands
17
+ - Enhanced error messages showing approved vs unapproved commands with helpful guidance
18
+
19
+ ### Added
20
+
21
+ - 19 comprehensive security tests for strict command whitelist enforcement
22
+ - Tests for unapproved non-dangerous commands (whoami, hostname)
23
+ - Tests for Windows-specific commands (dir, type, copy, move, ren, del, mkdir, rmdir, ipconfig)
24
+ - Regression tests ensuring all vulnerability examples are blocked
25
+ - Defense-in-depth tests for dangerous patterns on approved commands
26
+
27
+ ### Changed
28
+
29
+ - Updated 9 existing shell-tool tests to reflect new strict approval logic
30
+ - Updated error messages from "Command requires approval" to "Command not in approved list"
31
+ - Shell command path validation tests now include all necessary commands in approved list
32
+
33
+ ### Fixed
34
+
35
+ - `execute_shell` tool now properly blocks ALL unapproved commands regardless of `requiresApproval` parameter
36
+ - Closed security bypass where unapproved commands executed with default `requiresApproval=false`
37
+
8
38
  ## [1.1.6] - 2025-11-16
9
39
 
10
40
  ### Fixed
@@ -114,16 +114,26 @@ export async function handleShellTool(name, args) {
114
114
  // Extract root commands for approval checking
115
115
  const rootCommands = extractRootCommands(validatedArgs.command);
116
116
  const allApproved = rootCommands.every((cmd) => approvedCommands.has(cmd) || alwaysApprovedCommands.has(cmd));
117
- // Check for dangerous patterns
118
- const isDangerous = isDangerousCommand(validatedArgs.command);
119
- if (!allApproved && (validatedArgs.requiresApproval || isDangerous)) {
117
+ // SECURITY FIX: Block ALL unapproved commands immediately
118
+ // Previously, commands were only blocked if (!allApproved && (requiresApproval || isDangerous))
119
+ // This allowed unapproved non-dangerous commands to execute by default
120
+ if (!allApproved) {
120
121
  const unapprovedCommands = rootCommands.filter((cmd) => !approvedCommands.has(cmd) && !alwaysApprovedCommands.has(cmd));
121
- throw new Error(`Command requires approval. Unapproved commands: ${unapprovedCommands.join(", ")}\n` +
122
+ const approvedList = Array.from(approvedCommands).join(", ");
123
+ throw new Error(`Access denied: Command not in approved list.\n` +
124
+ `Unapproved commands: ${unapprovedCommands.join(", ")}\n` +
125
+ `Command: ${validatedArgs.command}\n\n` +
126
+ `Approved commands: ${approvedList || "(none configured)"}\n\n` +
127
+ `To execute this command, add it to --approved-commands configuration.`);
128
+ }
129
+ // SECURITY: Check dangerous patterns even for approved commands
130
+ // This provides defense-in-depth against accidentally approving dangerous commands
131
+ const isDangerous = isDangerousCommand(validatedArgs.command);
132
+ if (isDangerous && !validatedArgs.requiresApproval) {
133
+ throw new Error(`⚠️ Dangerous command pattern detected.\n` +
122
134
  `Command: ${validatedArgs.command}\n` +
123
- `${isDangerous
124
- ? "⚠️ Warning: This command matches dangerous patterns\n"
125
- : ""}` +
126
- `To approve, add these commands to --approved-commands or .env configuration.`);
135
+ `This command requires explicit approval.\n` +
136
+ `Set requiresApproval: true in the command arguments to proceed.`);
127
137
  }
128
138
  // SECURITY FIX: Validate working directory ALWAYS (not just if provided)
129
139
  // This prevents bypass via process.cwd() when workdir is omitted
@@ -150,7 +160,7 @@ export async function handleShellTool(name, args) {
150
160
  `Error: ${error instanceof Error ? error.message : String(error)}\n` +
151
161
  `\n` +
152
162
  `Allowed directories:\n` +
153
- allowedDirs.map(d => ` - ${d}`).join('\n') +
163
+ allowedDirs.map((d) => ` - ${d}`).join("\n") +
154
164
  `\n\n` +
155
165
  `To execute commands in this directory:\n` +
156
166
  ` 1. Register the directory using register_directory tool, OR\n` +
@@ -165,7 +175,7 @@ export async function handleShellTool(name, args) {
165
175
  if (allowedDirs.length === 0) {
166
176
  throw new Error(`Access denied: Command contains paths but no allowed directories are configured.\n` +
167
177
  `Extracted paths:\n` +
168
- extractedPaths.map(p => ` - ${p}`).join('\n') +
178
+ extractedPaths.map((p) => ` - ${p}`).join("\n") +
169
179
  `\n\nPlease configure allowed directories using --approved-folders or register_directory tool.`);
170
180
  }
171
181
  // Validate each extracted path
@@ -177,9 +187,9 @@ export async function handleShellTool(name, args) {
177
187
  }
178
188
  if (invalidPaths.length > 0) {
179
189
  throw new Error(`Access denied: Command contains paths outside allowed directories:\n` +
180
- invalidPaths.map(p => ` - ${p}`).join('\n') +
190
+ invalidPaths.map((p) => ` - ${p}`).join("\n") +
181
191
  `\n\nAllowed directories:\n` +
182
- allowedDirs.map(d => ` - ${d}`).join('\n') +
192
+ allowedDirs.map((d) => ` - ${d}`).join("\n") +
183
193
  `\n\nTo access these paths, register their parent directories using register_directory tool.`);
184
194
  }
185
195
  }
@@ -187,7 +197,7 @@ export async function handleShellTool(name, args) {
187
197
  catch (error) {
188
198
  // If path extraction fails, be conservative and block
189
199
  // (better to block than allow potentially unsafe commands)
190
- if (error instanceof Error && error.message.includes('Access denied')) {
200
+ if (error instanceof Error && error.message.includes("Access denied")) {
191
201
  throw error;
192
202
  }
193
203
  // For extraction errors, block the command to be safe
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@n0zer0d4y/vulcan-file-ops",
3
- "version": "1.1.6",
3
+ "version": "1.1.7",
4
4
  "mcpName": "io.github.n0zer0d4y/vulcan-file-ops",
5
5
  "description": "MCP server for AI assistants: read, write, edit, and manage files securely on local filesystem.",
6
6
  "license": "MIT",