@defai.digital/ax-cli 3.5.2 → 3.6.0

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.
Files changed (125) hide show
  1. package/.ax-cli/memory.json +8 -8
  2. package/README.md +27 -1
  3. package/dist/agent/chat-history-manager.d.ts +56 -0
  4. package/dist/agent/chat-history-manager.js +150 -0
  5. package/dist/agent/chat-history-manager.js.map +1 -0
  6. package/dist/agent/llm-agent.js +1 -1
  7. package/dist/agent/llm-agent.js.map +1 -1
  8. package/dist/agent/tool-manager.d.ts +39 -0
  9. package/dist/agent/tool-manager.js +76 -0
  10. package/dist/agent/tool-manager.js.map +1 -0
  11. package/dist/analyzers/ast/index.d.ts +9 -0
  12. package/dist/analyzers/ast/index.js +10 -0
  13. package/dist/analyzers/ast/index.js.map +1 -0
  14. package/dist/analyzers/ast/node-helpers.d.ts +81 -0
  15. package/dist/analyzers/ast/node-helpers.js +128 -0
  16. package/dist/analyzers/ast/node-helpers.js.map +1 -0
  17. package/dist/analyzers/ast/traverser.d.ts +67 -0
  18. package/dist/analyzers/ast/traverser.js +156 -0
  19. package/dist/analyzers/ast/traverser.js.map +1 -0
  20. package/dist/analyzers/best-practices/index.d.ts +10 -0
  21. package/dist/analyzers/best-practices/index.js +11 -0
  22. package/dist/analyzers/best-practices/index.js.map +1 -0
  23. package/dist/commands/setup.js +13 -5
  24. package/dist/commands/setup.js.map +1 -1
  25. package/dist/index.js +7 -0
  26. package/dist/index.js.map +1 -1
  27. package/dist/llm/client.d.ts +1 -0
  28. package/dist/llm/client.js +44 -0
  29. package/dist/llm/client.js.map +1 -1
  30. package/dist/mcp/ssrf-protection.d.ts +86 -0
  31. package/dist/mcp/ssrf-protection.js +313 -0
  32. package/dist/mcp/ssrf-protection.js.map +1 -0
  33. package/dist/mcp/validation.d.ts +4 -0
  34. package/dist/mcp/validation.js +122 -11
  35. package/dist/mcp/validation.js.map +1 -1
  36. package/dist/schemas/settings-schemas.d.ts +30 -0
  37. package/dist/schemas/settings-schemas.js +30 -0
  38. package/dist/schemas/settings-schemas.js.map +1 -1
  39. package/dist/tools/bash.d.ts +3 -2
  40. package/dist/tools/bash.js +31 -2
  41. package/dist/tools/bash.js.map +1 -1
  42. package/dist/tools/search.d.ts +1 -1
  43. package/dist/tools/search.js +121 -128
  44. package/dist/tools/search.js.map +1 -1
  45. package/dist/tools/text-editor.js +52 -15
  46. package/dist/tools/text-editor.js.map +1 -1
  47. package/dist/ui/components/status-bar.js +2 -2
  48. package/dist/ui/components/status-bar.js.map +1 -1
  49. package/dist/ui/components/toast-notification.js +0 -1
  50. package/dist/ui/components/toast-notification.js.map +1 -1
  51. package/dist/utils/audit-logger.d.ts +247 -0
  52. package/dist/utils/audit-logger.js +374 -0
  53. package/dist/utils/audit-logger.js.map +1 -0
  54. package/dist/utils/command-security.d.ts +85 -0
  55. package/dist/utils/command-security.js +200 -0
  56. package/dist/utils/command-security.js.map +1 -0
  57. package/dist/utils/encryption.d.ts +78 -0
  58. package/dist/utils/encryption.js +216 -0
  59. package/dist/utils/encryption.js.map +1 -0
  60. package/dist/utils/error-sanitizer.d.ts +119 -0
  61. package/dist/utils/error-sanitizer.js +253 -0
  62. package/dist/utils/error-sanitizer.js.map +1 -0
  63. package/dist/utils/input-sanitizer.d.ts +210 -0
  64. package/dist/utils/input-sanitizer.js +362 -0
  65. package/dist/utils/input-sanitizer.js.map +1 -0
  66. package/dist/utils/json-utils.d.ts +13 -0
  67. package/dist/utils/json-utils.js +55 -1
  68. package/dist/utils/json-utils.js.map +1 -1
  69. package/dist/utils/parallel-analyzer.js +29 -12
  70. package/dist/utils/parallel-analyzer.js.map +1 -1
  71. package/dist/utils/path-security.d.ts +90 -0
  72. package/dist/utils/path-security.js +328 -0
  73. package/dist/utils/path-security.js.map +1 -0
  74. package/dist/utils/process-pool.d.ts +105 -0
  75. package/dist/utils/process-pool.js +326 -0
  76. package/dist/utils/process-pool.js.map +1 -0
  77. package/dist/utils/rate-limiter.d.ts +207 -0
  78. package/dist/utils/rate-limiter.js +303 -0
  79. package/dist/utils/rate-limiter.js.map +1 -0
  80. package/dist/utils/settings-manager.js +83 -4
  81. package/dist/utils/settings-manager.js.map +1 -1
  82. package/eslint.config.js +3 -0
  83. package/package.json +1 -1
  84. package/.ax-cli/checkpoints/2025-11-20/checkpoint-11e9e0ba-c39d-4fd2-aa77-bc818811c921.json +0 -69
  85. package/.ax-cli/checkpoints/2025-11-20/checkpoint-2b260b98-b418-4c7c-9694-e2b94967e662.json +0 -24
  86. package/.ax-cli/checkpoints/2025-11-20/checkpoint-7e03601e-e8ab-4cd7-9841-a74b66adf78f.json +0 -69
  87. package/.ax-cli/checkpoints/2025-11-20/checkpoint-7f9c6562-771f-4fd0-adcf-9e7e9ac34ae8.json +0 -44
  88. package/.ax-cli/checkpoints/2025-11-20/checkpoint-e1ebe666-4c3a-4367-ba5c-27fe512a9c70.json +0 -24
  89. package/.ax-cli/checkpoints/2025-11-21/checkpoint-15743e7d-430c-4d76-b6fc-955d7a5c250c.json +0 -44
  90. package/.ax-cli/checkpoints/2025-11-21/checkpoint-25cf7679-0b3f-4988-83d7-704548fbba91.json +0 -69
  91. package/.ax-cli/checkpoints/2025-11-21/checkpoint-54aedbac-6db0-464e-8ebb-dbb3979e6dca.json +0 -24
  92. package/.ax-cli/checkpoints/2025-11-21/checkpoint-7658aed8-fe5d-4222-903f-1a7c63717ea7.json +0 -24
  93. package/.ax-cli/checkpoints/2025-11-21/checkpoint-c9c13497-40dc-4294-a327-6a5fc854eaa1.json +0 -69
  94. package/ax.config.json +0 -333
  95. package/dist/hooks/use-chat-reducer.d.ts +0 -61
  96. package/dist/hooks/use-chat-reducer.js +0 -118
  97. package/dist/hooks/use-chat-reducer.js.map +0 -1
  98. package/dist/hooks/use-enhanced-input.d.ts +0 -40
  99. package/dist/hooks/use-enhanced-input.js +0 -249
  100. package/dist/hooks/use-enhanced-input.js.map +0 -1
  101. package/dist/hooks/use-input-handler.d.ts +0 -46
  102. package/dist/hooks/use-input-handler.js +0 -1430
  103. package/dist/hooks/use-input-handler.js.map +0 -1
  104. package/dist/hooks/use-input-history.d.ts +0 -9
  105. package/dist/hooks/use-input-history.js +0 -112
  106. package/dist/hooks/use-input-history.js.map +0 -1
  107. package/dist/utils/paste-collapse.d.ts +0 -46
  108. package/dist/utils/paste-collapse.js +0 -77
  109. package/dist/utils/paste-collapse.js.map +0 -1
  110. package/packages/schemas/dist/index.d.ts +0 -14
  111. package/packages/schemas/dist/index.d.ts.map +0 -1
  112. package/packages/schemas/dist/index.js +0 -19
  113. package/packages/schemas/dist/index.js.map +0 -1
  114. package/packages/schemas/dist/public/core/brand-types.d.ts +0 -308
  115. package/packages/schemas/dist/public/core/brand-types.d.ts.map +0 -1
  116. package/packages/schemas/dist/public/core/brand-types.js +0 -243
  117. package/packages/schemas/dist/public/core/brand-types.js.map +0 -1
  118. package/packages/schemas/dist/public/core/enums.d.ts +0 -227
  119. package/packages/schemas/dist/public/core/enums.d.ts.map +0 -1
  120. package/packages/schemas/dist/public/core/enums.js +0 -222
  121. package/packages/schemas/dist/public/core/enums.js.map +0 -1
  122. package/packages/schemas/dist/public/core/id-types.d.ts +0 -286
  123. package/packages/schemas/dist/public/core/id-types.d.ts.map +0 -1
  124. package/packages/schemas/dist/public/core/id-types.js +0 -136
  125. package/packages/schemas/dist/public/core/id-types.js.map +0 -1
@@ -0,0 +1,374 @@
1
+ /**
2
+ * Security Audit Logging System (REQ-SEC-008)
3
+ *
4
+ * Provides tamper-proof logging for security-critical events
5
+ * Implements:
6
+ * - Cryptographic log integrity verification
7
+ * - Automatic log retention (90 days)
8
+ * - SIEM-ready structured logging
9
+ * - Critical event alerting
10
+ *
11
+ * Security: CVSS 6.1 (Medium Priority)
12
+ */
13
+ import { createHash } from 'crypto';
14
+ import { writeFileSync, readFileSync, existsSync, mkdirSync, readdirSync, unlinkSync, statSync } from 'fs';
15
+ import { join } from 'path';
16
+ import { homedir } from 'os';
17
+ /**
18
+ * Security event severity levels
19
+ */
20
+ export var AuditSeverity;
21
+ (function (AuditSeverity) {
22
+ AuditSeverity["INFO"] = "INFO";
23
+ AuditSeverity["WARNING"] = "WARNING";
24
+ AuditSeverity["ERROR"] = "ERROR";
25
+ AuditSeverity["CRITICAL"] = "CRITICAL";
26
+ })(AuditSeverity || (AuditSeverity = {}));
27
+ /**
28
+ * Security event categories
29
+ */
30
+ export var AuditCategory;
31
+ (function (AuditCategory) {
32
+ AuditCategory["AUTHENTICATION"] = "AUTHENTICATION";
33
+ AuditCategory["AUTHORIZATION"] = "AUTHORIZATION";
34
+ AuditCategory["DATA_ACCESS"] = "DATA_ACCESS";
35
+ AuditCategory["DATA_MODIFICATION"] = "DATA_MODIFICATION";
36
+ AuditCategory["COMMAND_EXECUTION"] = "COMMAND_EXECUTION";
37
+ AuditCategory["API_CALL"] = "API_CALL";
38
+ AuditCategory["RATE_LIMIT"] = "RATE_LIMIT";
39
+ AuditCategory["INPUT_VALIDATION"] = "INPUT_VALIDATION";
40
+ AuditCategory["ENCRYPTION"] = "ENCRYPTION";
41
+ AuditCategory["MCP_OPERATION"] = "MCP_OPERATION";
42
+ AuditCategory["FILE_OPERATION"] = "FILE_OPERATION";
43
+ AuditCategory["SYSTEM_EVENT"] = "SYSTEM_EVENT";
44
+ })(AuditCategory || (AuditCategory = {}));
45
+ /**
46
+ * Default configuration
47
+ */
48
+ const DEFAULT_CONFIG = {
49
+ logDirectory: join(homedir(), '.ax-cli', 'audit-logs'),
50
+ retentionDays: 90,
51
+ enableAlerts: true,
52
+ enableChaining: true,
53
+ maxFileSize: 10 * 1024 * 1024, // 10MB
54
+ };
55
+ /**
56
+ * Audit Logger
57
+ *
58
+ * Provides tamper-proof audit logging with cryptographic verification
59
+ *
60
+ * @example
61
+ * ```typescript
62
+ * const logger = AuditLogger.getInstance();
63
+ *
64
+ * // Log a security event
65
+ * logger.log({
66
+ * severity: AuditSeverity.WARNING,
67
+ * category: AuditCategory.RATE_LIMIT,
68
+ * action: 'rate_limit_exceeded',
69
+ * actor: 'user-123',
70
+ * outcome: 'failure',
71
+ * details: { limit: 20, attempts: 25 },
72
+ * });
73
+ *
74
+ * // Log critical event (triggers alert)
75
+ * logger.logCritical({
76
+ * category: AuditCategory.COMMAND_EXECUTION,
77
+ * action: 'shell_injection_attempt',
78
+ * outcome: 'failure',
79
+ * details: { command: 'ls; rm -rf /' },
80
+ * });
81
+ * ```
82
+ */
83
+ export class AuditLogger {
84
+ static instance = null;
85
+ config;
86
+ currentLogFile;
87
+ lastHash = null;
88
+ eventCount = 0;
89
+ alertCallbacks = [];
90
+ constructor(config = {}) {
91
+ this.config = { ...DEFAULT_CONFIG, ...config };
92
+ // Ensure log directory exists
93
+ if (!existsSync(this.config.logDirectory)) {
94
+ mkdirSync(this.config.logDirectory, { recursive: true });
95
+ }
96
+ // Initialize log file
97
+ this.currentLogFile = this.getCurrentLogFile();
98
+ // Load last hash for chaining
99
+ if (this.config.enableChaining) {
100
+ this.lastHash = this.loadLastHash();
101
+ }
102
+ // Start retention cleanup (run once on init)
103
+ this.cleanupOldLogs();
104
+ }
105
+ /**
106
+ * Get singleton instance
107
+ */
108
+ static getInstance(config) {
109
+ if (!AuditLogger.instance) {
110
+ AuditLogger.instance = new AuditLogger(config);
111
+ }
112
+ return AuditLogger.instance;
113
+ }
114
+ /**
115
+ * Reset singleton (for testing)
116
+ */
117
+ static resetInstance() {
118
+ AuditLogger.instance = null;
119
+ }
120
+ /**
121
+ * Register alert callback for critical events
122
+ */
123
+ onCriticalEvent(callback) {
124
+ this.alertCallbacks.push(callback);
125
+ }
126
+ /**
127
+ * Log an audit event
128
+ */
129
+ log(event) {
130
+ const fullEvent = {
131
+ id: this.generateEventId(),
132
+ timestamp: new Date().toISOString(),
133
+ ...event,
134
+ };
135
+ // Add hash chain for tamper detection
136
+ if (this.config.enableChaining) {
137
+ fullEvent.previousHash = this.lastHash || undefined;
138
+ fullEvent.hash = this.calculateHash(fullEvent);
139
+ this.lastHash = fullEvent.hash;
140
+ }
141
+ // Write to log file
142
+ this.writeEvent(fullEvent);
143
+ // Emit alert for critical events
144
+ if (this.config.enableAlerts && fullEvent.severity === AuditSeverity.CRITICAL) {
145
+ this.emitAlert(fullEvent);
146
+ }
147
+ // Check if we need to rotate log file
148
+ this.checkLogRotation();
149
+ this.eventCount++;
150
+ }
151
+ /**
152
+ * Log critical security event (convenience method)
153
+ */
154
+ logCritical(event) {
155
+ this.log({
156
+ ...event,
157
+ severity: AuditSeverity.CRITICAL,
158
+ });
159
+ }
160
+ /**
161
+ * Log warning event (convenience method)
162
+ */
163
+ logWarning(event) {
164
+ this.log({
165
+ ...event,
166
+ severity: AuditSeverity.WARNING,
167
+ });
168
+ }
169
+ /**
170
+ * Log error event (convenience method)
171
+ */
172
+ logError(event) {
173
+ this.log({
174
+ ...event,
175
+ severity: AuditSeverity.ERROR,
176
+ });
177
+ }
178
+ /**
179
+ * Log info event (convenience method)
180
+ */
181
+ logInfo(event) {
182
+ this.log({
183
+ ...event,
184
+ severity: AuditSeverity.INFO,
185
+ });
186
+ }
187
+ /**
188
+ * Verify log integrity
189
+ *
190
+ * Checks the hash chain to detect tampering
191
+ */
192
+ verifyIntegrity(logFile) {
193
+ const file = logFile || this.currentLogFile;
194
+ if (!existsSync(file)) {
195
+ return { valid: false, errors: ['Log file does not exist'] };
196
+ }
197
+ const errors = [];
198
+ const lines = readFileSync(file, 'utf8').split('\n').filter(l => l.trim());
199
+ let previousHash = null;
200
+ for (let i = 0; i < lines.length; i++) {
201
+ try {
202
+ const event = JSON.parse(lines[i]);
203
+ // Verify hash chain (normalize undefined to null for comparison)
204
+ const eventPrevHash = event.previousHash || null;
205
+ if (eventPrevHash !== previousHash) {
206
+ errors.push(`Event ${event.id} (line ${i + 1}): Hash chain broken. ` +
207
+ `Expected previous hash: ${previousHash}, got: ${eventPrevHash}`);
208
+ }
209
+ // Verify event hash
210
+ const calculatedHash = this.calculateHash(event);
211
+ if (event.hash !== calculatedHash) {
212
+ errors.push(`Event ${event.id} (line ${i + 1}): Hash mismatch. ` +
213
+ `Event may have been tampered with.`);
214
+ }
215
+ previousHash = event.hash || null;
216
+ }
217
+ catch (error) {
218
+ errors.push(`Line ${i + 1}: Invalid JSON - ${error instanceof Error ? error.message : 'Unknown error'}`);
219
+ }
220
+ }
221
+ return {
222
+ valid: errors.length === 0,
223
+ errors,
224
+ };
225
+ }
226
+ /**
227
+ * Get audit statistics
228
+ */
229
+ getStats() {
230
+ return {
231
+ totalEvents: this.eventCount,
232
+ logDirectory: this.config.logDirectory,
233
+ currentLogFile: this.currentLogFile,
234
+ retentionDays: this.config.retentionDays,
235
+ };
236
+ }
237
+ /**
238
+ * Generate unique event ID
239
+ */
240
+ generateEventId() {
241
+ const timestamp = Date.now();
242
+ const random = Math.random().toString(36).substring(2, 11);
243
+ return `evt_${timestamp}_${random}`;
244
+ }
245
+ /**
246
+ * Calculate SHA-256 hash of event (excluding hash field itself)
247
+ */
248
+ calculateHash(event) {
249
+ // Create copy without hash field
250
+ const { hash, ...eventWithoutHash } = event;
251
+ // Sort keys for consistent hashing, filter out undefined values
252
+ const sortedKeys = Object.keys(eventWithoutHash)
253
+ .filter(key => eventWithoutHash[key] !== undefined)
254
+ .sort();
255
+ const data = sortedKeys.map(key => {
256
+ const value = eventWithoutHash[key];
257
+ return `${key}:${JSON.stringify(value)}`;
258
+ }).join('|');
259
+ return createHash('sha256').update(data).digest('hex');
260
+ }
261
+ /**
262
+ * Write event to log file
263
+ */
264
+ writeEvent(event) {
265
+ const logLine = JSON.stringify(event) + '\n';
266
+ try {
267
+ writeFileSync(this.currentLogFile, logLine, { flag: 'a' });
268
+ }
269
+ catch (error) {
270
+ // Fallback: If current log file is locked/corrupted, create new one
271
+ console.error('Failed to write to audit log:', error);
272
+ this.rotateLogFile();
273
+ writeFileSync(this.currentLogFile, logLine, { flag: 'a' });
274
+ }
275
+ }
276
+ /**
277
+ * Get current log file path
278
+ */
279
+ getCurrentLogFile() {
280
+ const date = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
281
+ return join(this.config.logDirectory, `audit-${date}.jsonl`);
282
+ }
283
+ /**
284
+ * Load last hash from current log file
285
+ */
286
+ loadLastHash() {
287
+ if (!existsSync(this.currentLogFile)) {
288
+ return null;
289
+ }
290
+ try {
291
+ const lines = readFileSync(this.currentLogFile, 'utf8').split('\n').filter(l => l.trim());
292
+ if (lines.length === 0)
293
+ return null;
294
+ const lastEvent = JSON.parse(lines[lines.length - 1]);
295
+ return lastEvent.hash || null;
296
+ }
297
+ catch {
298
+ return null;
299
+ }
300
+ }
301
+ /**
302
+ * Check if log file needs rotation
303
+ */
304
+ checkLogRotation() {
305
+ try {
306
+ const stats = statSync(this.currentLogFile);
307
+ if (stats.size >= this.config.maxFileSize) {
308
+ this.rotateLogFile();
309
+ }
310
+ }
311
+ catch {
312
+ // File doesn't exist or can't be read - will be created on next write
313
+ }
314
+ // Check if date changed (new day)
315
+ const expectedFile = this.getCurrentLogFile();
316
+ if (expectedFile !== this.currentLogFile) {
317
+ this.rotateLogFile();
318
+ }
319
+ }
320
+ /**
321
+ * Rotate log file
322
+ */
323
+ rotateLogFile() {
324
+ this.currentLogFile = this.getCurrentLogFile();
325
+ this.lastHash = this.loadLastHash();
326
+ }
327
+ /**
328
+ * Clean up old log files (retention policy)
329
+ */
330
+ cleanupOldLogs() {
331
+ try {
332
+ if (!existsSync(this.config.logDirectory)) {
333
+ return;
334
+ }
335
+ const files = readdirSync(this.config.logDirectory);
336
+ const now = Date.now();
337
+ const retentionMs = this.config.retentionDays * 24 * 60 * 60 * 1000;
338
+ for (const file of files) {
339
+ if (!file.startsWith('audit-') || !file.endsWith('.jsonl')) {
340
+ continue;
341
+ }
342
+ const filePath = join(this.config.logDirectory, file);
343
+ const stats = statSync(filePath);
344
+ const age = now - stats.mtimeMs;
345
+ if (age > retentionMs) {
346
+ unlinkSync(filePath);
347
+ }
348
+ }
349
+ }
350
+ catch (error) {
351
+ console.error('Failed to clean up old audit logs:', error);
352
+ }
353
+ }
354
+ /**
355
+ * Emit alert for critical events
356
+ */
357
+ emitAlert(event) {
358
+ for (const callback of this.alertCallbacks) {
359
+ try {
360
+ callback(event);
361
+ }
362
+ catch (error) {
363
+ console.error('Alert callback failed:', error);
364
+ }
365
+ }
366
+ }
367
+ }
368
+ /**
369
+ * Get audit logger singleton
370
+ */
371
+ export function getAuditLogger(config) {
372
+ return AuditLogger.getInstance(config);
373
+ }
374
+ //# sourceMappingURL=audit-logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-logger.js","sourceRoot":"","sources":["../../src/utils/audit-logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Command Security Utilities
3
+ *
4
+ * Provides secure command execution with whitelisting and validation.
5
+ * Prevents command injection vulnerabilities (REQ-SEC-001).
6
+ *
7
+ * @module command-security
8
+ */
9
+ import type { ToolResult } from '../types/index.js';
10
+ /**
11
+ * Whitelist of safe commands allowed for execution.
12
+ * Only these commands can be executed via the BashTool.
13
+ *
14
+ * CRITICAL: Do not add arbitrary commands without security review.
15
+ */
16
+ export declare const SAFE_COMMANDS: readonly ["ls", "grep", "find", "cat", "head", "tail", "wc", "sort", "uniq", "cut", "awk", "sed", "pwd", "echo", "date", "whoami", "hostname", "git", "rg", "fd", "rm", "mkdir", "touch", "cp", "mv"];
17
+ export type SafeCommand = typeof SAFE_COMMANDS[number];
18
+ /**
19
+ * Parsed command structure
20
+ */
21
+ export interface ParsedCommand {
22
+ command: SafeCommand;
23
+ args: string[];
24
+ }
25
+ /**
26
+ * Command execution options
27
+ */
28
+ export interface CommandExecutionOptions {
29
+ cwd?: string;
30
+ timeout?: number;
31
+ maxBuffer?: number;
32
+ }
33
+ /**
34
+ * Sanitize environment variables for child process.
35
+ * Only includes safe environment variables to prevent injection.
36
+ *
37
+ * @param env - Original process environment
38
+ * @returns Sanitized environment object
39
+ */
40
+ export declare function sanitizeEnv(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
41
+ /**
42
+ * Parse a command string into command and arguments.
43
+ * Validates that the command is in the whitelist.
44
+ *
45
+ * @param commandString - Full command string (e.g., "ls -la /tmp")
46
+ * @returns Parsed command structure
47
+ * @throws Error if command is not whitelisted
48
+ */
49
+ export declare function parseCommand(commandString: string): ParsedCommand;
50
+ /**
51
+ * Validate command arguments for shell metacharacters.
52
+ * Prevents command injection via argument injection.
53
+ *
54
+ * @param args - Command arguments to validate
55
+ * @returns Validation result
56
+ */
57
+ export declare function validateArguments(args: string[]): {
58
+ valid: boolean;
59
+ errors: string[];
60
+ };
61
+ /**
62
+ * Execute a safe command with validation.
63
+ * Uses execFile to avoid shell invocation and command injection.
64
+ *
65
+ * SECURITY: This function uses execFile instead of spawn('bash', ['-c'])
66
+ * to prevent command injection attacks.
67
+ *
68
+ * @param commandString - Command to execute
69
+ * @param options - Execution options
70
+ * @returns Tool result with output or error
71
+ */
72
+ export declare function executeSafeCommand(commandString: string, options?: CommandExecutionOptions): Promise<ToolResult>;
73
+ /**
74
+ * Check if a command is safe to execute.
75
+ *
76
+ * @param command - Command name to check
77
+ * @returns True if command is in whitelist
78
+ */
79
+ export declare function isSafeCommand(command: string): command is SafeCommand;
80
+ /**
81
+ * Get list of safe commands (for documentation/help).
82
+ *
83
+ * @returns Array of safe command names
84
+ */
85
+ export declare function getSafeCommands(): readonly string[];
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Command Security Utilities
3
+ *
4
+ * Provides secure command execution with whitelisting and validation.
5
+ * Prevents command injection vulnerabilities (REQ-SEC-001).
6
+ *
7
+ * @module command-security
8
+ */
9
+ import { execFile } from 'child_process';
10
+ import { promisify } from 'util';
11
+ const execFileAsync = promisify(execFile);
12
+ /**
13
+ * Whitelist of safe commands allowed for execution.
14
+ * Only these commands can be executed via the BashTool.
15
+ *
16
+ * CRITICAL: Do not add arbitrary commands without security review.
17
+ */
18
+ export const SAFE_COMMANDS = [
19
+ 'ls',
20
+ 'grep',
21
+ 'find',
22
+ 'cat',
23
+ 'head',
24
+ 'tail',
25
+ 'wc',
26
+ 'sort',
27
+ 'uniq',
28
+ 'cut',
29
+ 'awk',
30
+ 'sed',
31
+ 'pwd',
32
+ 'echo',
33
+ 'date',
34
+ 'whoami',
35
+ 'hostname',
36
+ 'git',
37
+ 'rg',
38
+ 'fd',
39
+ 'rm', // File deletion (safe with validation)
40
+ 'mkdir', // Directory creation
41
+ 'touch', // File creation
42
+ 'cp', // File copy
43
+ 'mv', // File move/rename
44
+ ];
45
+ /**
46
+ * Environment variables safe to pass to child processes.
47
+ * Only these will be included in the child process environment.
48
+ */
49
+ const SAFE_ENV_VARS = [
50
+ 'PATH',
51
+ 'HOME',
52
+ 'USER',
53
+ 'LANG',
54
+ 'LC_ALL',
55
+ 'TERM',
56
+ 'TMPDIR',
57
+ 'PWD',
58
+ ];
59
+ /**
60
+ * Shell metacharacters that are forbidden in command arguments.
61
+ * These could enable command injection if not properly validated.
62
+ */
63
+ const SHELL_METACHARACTERS = /[;&|`$(){}[\]<>'"\\*?~!#]/;
64
+ /**
65
+ * Sanitize environment variables for child process.
66
+ * Only includes safe environment variables to prevent injection.
67
+ *
68
+ * @param env - Original process environment
69
+ * @returns Sanitized environment object
70
+ */
71
+ export function sanitizeEnv(env) {
72
+ const sanitized = {};
73
+ for (const key of SAFE_ENV_VARS) {
74
+ if (env[key]) {
75
+ sanitized[key] = env[key];
76
+ }
77
+ }
78
+ return sanitized;
79
+ }
80
+ /**
81
+ * Parse a command string into command and arguments.
82
+ * Validates that the command is in the whitelist.
83
+ *
84
+ * @param commandString - Full command string (e.g., "ls -la /tmp")
85
+ * @returns Parsed command structure
86
+ * @throws Error if command is not whitelisted
87
+ */
88
+ export function parseCommand(commandString) {
89
+ const trimmed = commandString.trim();
90
+ if (!trimmed) {
91
+ throw new Error('Empty command string');
92
+ }
93
+ // Simple split by whitespace
94
+ const parts = trimmed.split(/\s+/);
95
+ const command = parts[0];
96
+ const args = parts.slice(1);
97
+ // Validate command is in whitelist
98
+ if (!SAFE_COMMANDS.includes(command)) {
99
+ throw new Error(`Command '${command}' not in whitelist. Allowed commands: ${SAFE_COMMANDS.join(', ')}`);
100
+ }
101
+ return {
102
+ command: command,
103
+ args,
104
+ };
105
+ }
106
+ /**
107
+ * Validate command arguments for shell metacharacters.
108
+ * Prevents command injection via argument injection.
109
+ *
110
+ * @param args - Command arguments to validate
111
+ * @returns Validation result
112
+ */
113
+ export function validateArguments(args) {
114
+ const errors = [];
115
+ for (let i = 0; i < args.length; i++) {
116
+ const arg = args[i];
117
+ // Check for shell metacharacters
118
+ if (SHELL_METACHARACTERS.test(arg)) {
119
+ errors.push(`Argument ${i} contains forbidden shell metacharacters: "${arg}"`);
120
+ }
121
+ // Check for null bytes
122
+ if (arg.includes('\0')) {
123
+ errors.push(`Argument ${i} contains null byte`);
124
+ }
125
+ // Check length (prevent buffer overflow)
126
+ if (arg.length > 10000) {
127
+ errors.push(`Argument ${i} exceeds maximum length (10000 chars)`);
128
+ }
129
+ }
130
+ return {
131
+ valid: errors.length === 0,
132
+ errors,
133
+ };
134
+ }
135
+ /**
136
+ * Execute a safe command with validation.
137
+ * Uses execFile to avoid shell invocation and command injection.
138
+ *
139
+ * SECURITY: This function uses execFile instead of spawn('bash', ['-c'])
140
+ * to prevent command injection attacks.
141
+ *
142
+ * @param commandString - Command to execute
143
+ * @param options - Execution options
144
+ * @returns Tool result with output or error
145
+ */
146
+ export async function executeSafeCommand(commandString, options = {}) {
147
+ try {
148
+ // 1. Parse command into command + args
149
+ const parsed = parseCommand(commandString);
150
+ // 2. Validate arguments
151
+ const validation = validateArguments(parsed.args);
152
+ if (!validation.valid) {
153
+ return {
154
+ success: false,
155
+ error: `Command validation failed:\n${validation.errors.join('\n')}`,
156
+ };
157
+ }
158
+ // 3. Prepare execution options
159
+ const execOptions = {
160
+ cwd: options.cwd || process.cwd(),
161
+ env: sanitizeEnv(process.env),
162
+ timeout: options.timeout || 30000, // 30 second default
163
+ maxBuffer: options.maxBuffer || 1024 * 1024, // 1MB default
164
+ };
165
+ // 4. Execute using execFile (no shell invocation)
166
+ const { stdout, stderr } = await execFileAsync(parsed.command, parsed.args, execOptions);
167
+ // 5. Return successful result
168
+ return {
169
+ success: true,
170
+ output: stdout || stderr || 'Command completed successfully',
171
+ };
172
+ }
173
+ catch (error) {
174
+ // Handle execution errors
175
+ const errorMessage = error.message || String(error);
176
+ const exitCode = error.code || 'unknown';
177
+ return {
178
+ success: false,
179
+ error: `Command execution failed (exit code: ${exitCode}): ${errorMessage}`,
180
+ };
181
+ }
182
+ }
183
+ /**
184
+ * Check if a command is safe to execute.
185
+ *
186
+ * @param command - Command name to check
187
+ * @returns True if command is in whitelist
188
+ */
189
+ export function isSafeCommand(command) {
190
+ return SAFE_COMMANDS.includes(command);
191
+ }
192
+ /**
193
+ * Get list of safe commands (for documentation/help).
194
+ *
195
+ * @returns Array of safe command names
196
+ */
197
+ export function getSafeCommands() {
198
+ return SAFE_COMMANDS;
199
+ }
200
+ //# sourceMappingURL=command-security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-security.js","sourceRoot":"","sources":["../../src/utils/command-security.ts"],"names":[],"mappings":"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"}