@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 +30 -0
- package/dist/tools/shell-tool.js +23 -13
- package/package.json +1 -1
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
|
package/dist/tools/shell-tool.js
CHANGED
|
@@ -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
|
-
//
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
|
|
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
|
-
|
|
124
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
190
|
+
invalidPaths.map((p) => ` - ${p}`).join("\n") +
|
|
181
191
|
`\n\nAllowed directories:\n` +
|
|
182
|
-
allowedDirs.map(d => ` - ${d}`).join(
|
|
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(
|
|
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.
|
|
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",
|