@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,210 @@
1
+ /**
2
+ * Input Sanitization Framework (REQ-SEC-007)
3
+ *
4
+ * Provides comprehensive input validation and sanitization to prevent:
5
+ * - ReDoS (Regular Expression Denial of Service)
6
+ * - Command injection
7
+ * - Path traversal
8
+ * - Unicode attacks
9
+ * - Buffer overflow
10
+ *
11
+ * Security: CVSS 7.3 (High Priority)
12
+ */
13
+ /**
14
+ * Sanitization result with validation and cleaned value
15
+ */
16
+ export interface SanitizationResult {
17
+ /**
18
+ * Whether the input passed validation
19
+ */
20
+ valid: boolean;
21
+ /**
22
+ * Sanitized/cleaned value (only if valid)
23
+ */
24
+ value?: string;
25
+ /**
26
+ * Error message if validation failed
27
+ */
28
+ error?: string;
29
+ /**
30
+ * Warning messages (non-fatal issues)
31
+ */
32
+ warnings?: string[];
33
+ }
34
+ /**
35
+ * Configuration for input sanitization
36
+ */
37
+ export interface SanitizerOptions {
38
+ /**
39
+ * Maximum allowed length (default: 10,000 characters)
40
+ */
41
+ maxLength?: number;
42
+ /**
43
+ * Whether to normalize Unicode (default: true)
44
+ */
45
+ normalizeUnicode?: boolean;
46
+ /**
47
+ * Character whitelist pattern (regex)
48
+ */
49
+ allowedPattern?: RegExp;
50
+ /**
51
+ * Whether to trim whitespace (default: true)
52
+ */
53
+ trim?: boolean;
54
+ /**
55
+ * Whether to allow empty strings (default: false)
56
+ */
57
+ allowEmpty?: boolean;
58
+ }
59
+ /**
60
+ * Default maximum input lengths for different contexts
61
+ */
62
+ export declare const MAX_INPUT_LENGTHS: {
63
+ readonly COMMAND: 10000;
64
+ readonly FILE_PATH: 4096;
65
+ readonly USER_INPUT: 50000;
66
+ readonly SEARCH_QUERY: 1000;
67
+ readonly ENV_VALUE: 10000;
68
+ readonly CONFIG_VALUE: 10000;
69
+ };
70
+ /**
71
+ * Safe characters for different contexts
72
+ */
73
+ export declare const SAFE_PATTERNS: {
74
+ /**
75
+ * Alphanumeric, spaces, and common punctuation
76
+ */
77
+ readonly BASIC: RegExp;
78
+ /**
79
+ * Safe for file paths (no directory traversal)
80
+ */
81
+ readonly FILE_PATH: RegExp;
82
+ /**
83
+ * Safe for environment variable values
84
+ */
85
+ readonly ENV_VALUE: RegExp;
86
+ /**
87
+ * Printable ASCII only (most restrictive)
88
+ */
89
+ readonly ASCII_PRINTABLE: RegExp;
90
+ };
91
+ /**
92
+ * Normalize Unicode string to prevent homograph attacks
93
+ *
94
+ * Uses NFC (Canonical Decomposition, followed by Canonical Composition)
95
+ * which is the recommended normalization form for most use cases
96
+ *
97
+ * @param input - String to normalize
98
+ * @returns Normalized string
99
+ */
100
+ export declare function normalizeUnicode(input: string): string;
101
+ /**
102
+ * Check for dangerous patterns in input
103
+ *
104
+ * @param input - String to check
105
+ * @returns Array of detected dangerous patterns
106
+ */
107
+ export declare function detectDangerousPatterns(input: string): string[];
108
+ /**
109
+ * Sanitize general user input with configurable options
110
+ *
111
+ * @param input - Raw input string
112
+ * @param options - Sanitization options
113
+ * @returns Sanitization result
114
+ *
115
+ * @example
116
+ * ```typescript
117
+ * const result = sanitizeInput('User input here', {
118
+ * maxLength: 1000,
119
+ * normalizeUnicode: true,
120
+ * allowedPattern: SAFE_PATTERNS.BASIC,
121
+ * });
122
+ *
123
+ * if (result.valid) {
124
+ * // Use result.value safely
125
+ * } else {
126
+ * console.error(result.error);
127
+ * }
128
+ * ```
129
+ */
130
+ export declare function sanitizeInput(input: string, options?: SanitizerOptions): SanitizationResult;
131
+ /**
132
+ * Sanitize file path input to prevent path traversal
133
+ *
134
+ * @param path - File path to sanitize
135
+ * @returns Sanitization result
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * const result = sanitizeFilePath('../../../etc/passwd');
140
+ * if (!result.valid) {
141
+ * console.error('Invalid path:', result.error);
142
+ * }
143
+ * ```
144
+ */
145
+ export declare function sanitizeFilePath(path: string): SanitizationResult;
146
+ /**
147
+ * Sanitize shell command input
148
+ *
149
+ * NOTE: This is a last line of defense. Prefer execFile over exec
150
+ * and use argument arrays instead of concatenating commands.
151
+ *
152
+ * @param command - Command string to sanitize
153
+ * @returns Sanitization result
154
+ *
155
+ * @example
156
+ * ```typescript
157
+ * const result = sanitizeCommand('ls -la');
158
+ * if (result.valid) {
159
+ * // Still prefer execFile with args array
160
+ * execFile(result.value.split(' ')[0], result.value.split(' ').slice(1));
161
+ * }
162
+ * ```
163
+ */
164
+ export declare function sanitizeCommand(command: string): SanitizationResult;
165
+ /**
166
+ * Sanitize search query input
167
+ *
168
+ * @param query - Search query to sanitize
169
+ * @returns Sanitization result
170
+ */
171
+ export declare function sanitizeSearchQuery(query: string): SanitizationResult;
172
+ /**
173
+ * Sanitize environment variable value
174
+ *
175
+ * @param value - Environment variable value to sanitize
176
+ * @returns Sanitization result
177
+ */
178
+ export declare function sanitizeEnvValue(value: string): SanitizationResult;
179
+ /**
180
+ * Escape shell arguments for safe execution
181
+ *
182
+ * NOTE: This is a defense-in-depth measure. Always prefer:
183
+ * 1. execFile with argument array over exec
184
+ * 2. Argument validation/whitelisting
185
+ * 3. This escaping function as a last resort
186
+ *
187
+ * @param arg - Argument to escape
188
+ * @returns Safely escaped argument
189
+ */
190
+ export declare function escapeShellArg(arg: string): string;
191
+ /**
192
+ * Validate regex pattern for ReDoS protection
193
+ *
194
+ * Checks for common ReDoS patterns:
195
+ * - Nested quantifiers (e.g., (a+)+)
196
+ * - Alternation with overlapping patterns
197
+ * - Excessive backtracking potential
198
+ *
199
+ * @param pattern - Regex pattern to validate
200
+ * @returns Validation result
201
+ *
202
+ * @example
203
+ * ```typescript
204
+ * const result = validateRegexPattern('(a+)+b');
205
+ * if (!result.valid) {
206
+ * console.error('Unsafe regex:', result.error);
207
+ * }
208
+ * ```
209
+ */
210
+ export declare function validateRegexPattern(pattern: string): SanitizationResult;
@@ -0,0 +1,362 @@
1
+ /**
2
+ * Input Sanitization Framework (REQ-SEC-007)
3
+ *
4
+ * Provides comprehensive input validation and sanitization to prevent:
5
+ * - ReDoS (Regular Expression Denial of Service)
6
+ * - Command injection
7
+ * - Path traversal
8
+ * - Unicode attacks
9
+ * - Buffer overflow
10
+ *
11
+ * Security: CVSS 7.3 (High Priority)
12
+ */
13
+ /**
14
+ * Default maximum input lengths for different contexts
15
+ */
16
+ export const MAX_INPUT_LENGTHS = {
17
+ COMMAND: 10_000, // Shell commands
18
+ FILE_PATH: 4_096, // File system paths
19
+ USER_INPUT: 50_000, // General user input (prompts, etc.)
20
+ SEARCH_QUERY: 1_000, // Search queries
21
+ ENV_VALUE: 10_000, // Environment variable values
22
+ CONFIG_VALUE: 10_000, // Configuration values
23
+ };
24
+ /**
25
+ * Dangerous patterns that indicate potential attacks
26
+ * These patterns are designed to be fast and avoid ReDoS
27
+ */
28
+ const DANGEROUS_PATTERNS = {
29
+ // Null bytes (path traversal, command injection)
30
+ NULL_BYTE: /\0/,
31
+ // Excessive repetition (ReDoS indicator)
32
+ // Using fixed quantifier to prevent ReDoS
33
+ EXCESSIVE_REPETITION: /(.)\1{100,}/,
34
+ // Control characters (except common ones like \n, \t)
35
+ CONTROL_CHARS: /[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]/,
36
+ // Unicode direction override (used in homograph attacks)
37
+ UNICODE_OVERRIDE: /[\u202A-\u202E\u2066-\u2069]/,
38
+ };
39
+ /**
40
+ * Safe characters for different contexts
41
+ */
42
+ export const SAFE_PATTERNS = {
43
+ /**
44
+ * Alphanumeric, spaces, and common punctuation
45
+ */
46
+ BASIC: /^[a-zA-Z0-9\s.,!?'"()\-_]+$/,
47
+ /**
48
+ * Safe for file paths (no directory traversal)
49
+ */
50
+ FILE_PATH: /^[a-zA-Z0-9/._\-]+$/,
51
+ /**
52
+ * Safe for environment variable values
53
+ */
54
+ ENV_VALUE: /^[a-zA-Z0-9._\-:/=]+$/,
55
+ /**
56
+ * Printable ASCII only (most restrictive)
57
+ */
58
+ ASCII_PRINTABLE: /^[\x20-\x7E]+$/,
59
+ };
60
+ /**
61
+ * Normalize Unicode string to prevent homograph attacks
62
+ *
63
+ * Uses NFC (Canonical Decomposition, followed by Canonical Composition)
64
+ * which is the recommended normalization form for most use cases
65
+ *
66
+ * @param input - String to normalize
67
+ * @returns Normalized string
68
+ */
69
+ export function normalizeUnicode(input) {
70
+ return input.normalize('NFC');
71
+ }
72
+ /**
73
+ * Check for dangerous patterns in input
74
+ *
75
+ * @param input - String to check
76
+ * @returns Array of detected dangerous patterns
77
+ */
78
+ export function detectDangerousPatterns(input) {
79
+ const detected = [];
80
+ if (DANGEROUS_PATTERNS.NULL_BYTE.test(input)) {
81
+ detected.push('Null byte detected');
82
+ }
83
+ if (DANGEROUS_PATTERNS.EXCESSIVE_REPETITION.test(input)) {
84
+ detected.push('Excessive character repetition detected');
85
+ }
86
+ if (DANGEROUS_PATTERNS.CONTROL_CHARS.test(input)) {
87
+ detected.push('Control characters detected');
88
+ }
89
+ if (DANGEROUS_PATTERNS.UNICODE_OVERRIDE.test(input)) {
90
+ detected.push('Unicode direction override detected');
91
+ }
92
+ return detected;
93
+ }
94
+ /**
95
+ * Sanitize general user input with configurable options
96
+ *
97
+ * @param input - Raw input string
98
+ * @param options - Sanitization options
99
+ * @returns Sanitization result
100
+ *
101
+ * @example
102
+ * ```typescript
103
+ * const result = sanitizeInput('User input here', {
104
+ * maxLength: 1000,
105
+ * normalizeUnicode: true,
106
+ * allowedPattern: SAFE_PATTERNS.BASIC,
107
+ * });
108
+ *
109
+ * if (result.valid) {
110
+ * // Use result.value safely
111
+ * } else {
112
+ * console.error(result.error);
113
+ * }
114
+ * ```
115
+ */
116
+ export function sanitizeInput(input, options = {}) {
117
+ const { maxLength = MAX_INPUT_LENGTHS.USER_INPUT, normalizeUnicode: shouldNormalize = true, allowedPattern, trim = true, allowEmpty = false, } = options;
118
+ const warnings = [];
119
+ let value = input;
120
+ // 1. Trim if requested
121
+ if (trim) {
122
+ value = value.trim();
123
+ }
124
+ // 2. Check if empty
125
+ if (!allowEmpty && value.length === 0) {
126
+ return {
127
+ valid: false,
128
+ error: 'Input cannot be empty',
129
+ };
130
+ }
131
+ // 3. Check length BEFORE normalization (prevent DoS via normalization)
132
+ if (value.length > maxLength) {
133
+ return {
134
+ valid: false,
135
+ error: `Input exceeds maximum length of ${maxLength} characters (got ${value.length})`,
136
+ };
137
+ }
138
+ // 4. Unicode normalization (prevent homograph attacks)
139
+ if (shouldNormalize) {
140
+ const normalized = normalizeUnicode(value);
141
+ if (normalized !== value) {
142
+ warnings.push('Input was normalized (Unicode)');
143
+ value = normalized;
144
+ }
145
+ }
146
+ // 5. Check for dangerous patterns
147
+ const dangerous = detectDangerousPatterns(value);
148
+ if (dangerous.length > 0) {
149
+ return {
150
+ valid: false,
151
+ error: `Dangerous patterns detected: ${dangerous.join(', ')}`,
152
+ };
153
+ }
154
+ // 6. Apply character whitelist if provided
155
+ if (allowedPattern && !allowedPattern.test(value)) {
156
+ return {
157
+ valid: false,
158
+ error: 'Input contains disallowed characters',
159
+ };
160
+ }
161
+ return {
162
+ valid: true,
163
+ value,
164
+ warnings: warnings.length > 0 ? warnings : undefined,
165
+ };
166
+ }
167
+ /**
168
+ * Sanitize file path input to prevent path traversal
169
+ *
170
+ * @param path - File path to sanitize
171
+ * @returns Sanitization result
172
+ *
173
+ * @example
174
+ * ```typescript
175
+ * const result = sanitizeFilePath('../../../etc/passwd');
176
+ * if (!result.valid) {
177
+ * console.error('Invalid path:', result.error);
178
+ * }
179
+ * ```
180
+ */
181
+ export function sanitizeFilePath(path) {
182
+ const result = sanitizeInput(path, {
183
+ maxLength: MAX_INPUT_LENGTHS.FILE_PATH,
184
+ trim: true,
185
+ allowEmpty: false,
186
+ });
187
+ if (!result.valid) {
188
+ return result;
189
+ }
190
+ const value = result.value;
191
+ // Additional path-specific checks
192
+ const warnings = result.warnings || [];
193
+ // Check for path traversal patterns
194
+ if (value.includes('..')) {
195
+ warnings.push('Path contains parent directory references (..)');
196
+ }
197
+ // Check for absolute paths (may be intentional, so just warn)
198
+ if (value.startsWith('/') || /^[A-Z]:/i.test(value)) {
199
+ warnings.push('Absolute path detected');
200
+ }
201
+ // Check for hidden files (Unix)
202
+ if (value.split('/').some(part => part.startsWith('.'))) {
203
+ warnings.push('Path contains hidden file/directory');
204
+ }
205
+ return {
206
+ valid: true,
207
+ value,
208
+ warnings: warnings.length > 0 ? warnings : undefined,
209
+ };
210
+ }
211
+ /**
212
+ * Sanitize shell command input
213
+ *
214
+ * NOTE: This is a last line of defense. Prefer execFile over exec
215
+ * and use argument arrays instead of concatenating commands.
216
+ *
217
+ * @param command - Command string to sanitize
218
+ * @returns Sanitization result
219
+ *
220
+ * @example
221
+ * ```typescript
222
+ * const result = sanitizeCommand('ls -la');
223
+ * if (result.valid) {
224
+ * // Still prefer execFile with args array
225
+ * execFile(result.value.split(' ')[0], result.value.split(' ').slice(1));
226
+ * }
227
+ * ```
228
+ */
229
+ export function sanitizeCommand(command) {
230
+ const result = sanitizeInput(command, {
231
+ maxLength: MAX_INPUT_LENGTHS.COMMAND,
232
+ trim: true,
233
+ allowEmpty: false,
234
+ });
235
+ if (!result.valid) {
236
+ return result;
237
+ }
238
+ const value = result.value;
239
+ // Check for shell metacharacters that could enable injection
240
+ const shellMetaChars = /[;&|`$()<>\\]/;
241
+ if (shellMetaChars.test(value)) {
242
+ return {
243
+ valid: false,
244
+ error: 'Command contains dangerous shell metacharacters',
245
+ };
246
+ }
247
+ return {
248
+ valid: true,
249
+ value,
250
+ warnings: result.warnings,
251
+ };
252
+ }
253
+ /**
254
+ * Sanitize search query input
255
+ *
256
+ * @param query - Search query to sanitize
257
+ * @returns Sanitization result
258
+ */
259
+ export function sanitizeSearchQuery(query) {
260
+ return sanitizeInput(query, {
261
+ maxLength: MAX_INPUT_LENGTHS.SEARCH_QUERY,
262
+ trim: true,
263
+ allowEmpty: false,
264
+ });
265
+ }
266
+ /**
267
+ * Sanitize environment variable value
268
+ *
269
+ * @param value - Environment variable value to sanitize
270
+ * @returns Sanitization result
271
+ */
272
+ export function sanitizeEnvValue(value) {
273
+ return sanitizeInput(value, {
274
+ maxLength: MAX_INPUT_LENGTHS.ENV_VALUE,
275
+ trim: true,
276
+ allowEmpty: true, // Empty env vars are valid
277
+ });
278
+ }
279
+ /**
280
+ * Escape shell arguments for safe execution
281
+ *
282
+ * NOTE: This is a defense-in-depth measure. Always prefer:
283
+ * 1. execFile with argument array over exec
284
+ * 2. Argument validation/whitelisting
285
+ * 3. This escaping function as a last resort
286
+ *
287
+ * @param arg - Argument to escape
288
+ * @returns Safely escaped argument
289
+ */
290
+ export function escapeShellArg(arg) {
291
+ // On Windows, use double quotes
292
+ if (process.platform === 'win32') {
293
+ // Escape double quotes and backslashes
294
+ return `"${arg.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
295
+ }
296
+ // On Unix, use single quotes (safest - no interpolation)
297
+ // To include a single quote, end the quote, add escaped quote, resume quote
298
+ return `'${arg.replace(/'/g, "'\\''")}'`;
299
+ }
300
+ /**
301
+ * Validate regex pattern for ReDoS protection
302
+ *
303
+ * Checks for common ReDoS patterns:
304
+ * - Nested quantifiers (e.g., (a+)+)
305
+ * - Alternation with overlapping patterns
306
+ * - Excessive backtracking potential
307
+ *
308
+ * @param pattern - Regex pattern to validate
309
+ * @returns Validation result
310
+ *
311
+ * @example
312
+ * ```typescript
313
+ * const result = validateRegexPattern('(a+)+b');
314
+ * if (!result.valid) {
315
+ * console.error('Unsafe regex:', result.error);
316
+ * }
317
+ * ```
318
+ */
319
+ export function validateRegexPattern(pattern) {
320
+ // Check length first
321
+ if (pattern.length > 1000) {
322
+ return {
323
+ valid: false,
324
+ error: 'Regex pattern too long (max 1000 characters)',
325
+ };
326
+ }
327
+ const warnings = [];
328
+ // Check for nested quantifiers (major ReDoS risk)
329
+ // Pattern: quantifier inside a group that is itself quantified
330
+ const nestedQuantifiers = /\([^)]*[*+?{][^)]*\)[*+?{]/;
331
+ if (nestedQuantifiers.test(pattern)) {
332
+ return {
333
+ valid: false,
334
+ error: 'Regex contains nested quantifiers (ReDoS risk)',
335
+ };
336
+ }
337
+ // Check for excessive alternation
338
+ const alternations = pattern.split('|');
339
+ if (alternations.length > 20) {
340
+ warnings.push('Regex has many alternations (may be slow)');
341
+ }
342
+ // Check for backreferences (can cause exponential backtracking)
343
+ if (/\\[1-9]/.test(pattern)) {
344
+ warnings.push('Regex contains backreferences (may be slow)');
345
+ }
346
+ // Try to compile the regex to catch syntax errors
347
+ try {
348
+ new RegExp(pattern);
349
+ }
350
+ catch (error) {
351
+ return {
352
+ valid: false,
353
+ error: `Invalid regex: ${error instanceof Error ? error.message : 'Unknown error'}`,
354
+ };
355
+ }
356
+ return {
357
+ valid: true,
358
+ value: pattern,
359
+ warnings: warnings.length > 0 ? warnings : undefined,
360
+ };
361
+ }
362
+ //# sourceMappingURL=input-sanitizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-sanitizer.js","sourceRoot":"","sources":["../../src/utils/input-sanitizer.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,11 @@
1
1
  /**
2
2
  * JSON Parsing Utilities
3
3
  * Centralized JSON operations with validation and error handling
4
+ *
5
+ * Security: REQ-SEC-005 - Prototype Pollution Prevention
6
+ * - Sanitizes dangerous keys (__proto__, constructor, prototype)
7
+ * - Validates JSON structure before use
8
+ * - Prevents object property injection attacks
4
9
  */
5
10
  import { z } from 'zod';
6
11
  /**
@@ -57,3 +62,11 @@ export declare function parseJsonWithFallback<T>(jsonString: string, fallback: T
57
62
  * Parse JSON file with fallback value on error
58
63
  */
59
64
  export declare function parseJsonFileWithFallback<T>(filePath: string, fallback: T, schema?: z.ZodSchema<T>): T;
65
+ /**
66
+ * Sanitize an object to prevent prototype pollution
67
+ * Exported for testing purposes
68
+ *
69
+ * @param obj - Object to sanitize
70
+ * @returns Sanitized object
71
+ */
72
+ export declare function sanitizeJson<T>(obj: T): T;
@@ -1,15 +1,59 @@
1
1
  /**
2
2
  * JSON Parsing Utilities
3
3
  * Centralized JSON operations with validation and error handling
4
+ *
5
+ * Security: REQ-SEC-005 - Prototype Pollution Prevention
6
+ * - Sanitizes dangerous keys (__proto__, constructor, prototype)
7
+ * - Validates JSON structure before use
8
+ * - Prevents object property injection attacks
4
9
  */
5
10
  import { readFileSync, writeFileSync, renameSync, unlinkSync, existsSync, copyFileSync, mkdirSync } from 'fs';
6
11
  import { dirname } from 'path';
12
+ /**
13
+ * Dangerous keys that can cause prototype pollution
14
+ * These keys should never be allowed in parsed JSON
15
+ */
16
+ const DANGEROUS_KEYS = ['__proto__', 'constructor', 'prototype'];
17
+ /**
18
+ * Sanitize parsed JSON by removing dangerous keys
19
+ * Prevents prototype pollution attacks (REQ-SEC-005)
20
+ *
21
+ * @param obj - Object to sanitize (recursively)
22
+ * @returns Sanitized object with dangerous keys removed
23
+ */
24
+ function sanitizeObject(obj) {
25
+ if (obj === null || typeof obj !== 'object') {
26
+ return obj;
27
+ }
28
+ // Handle arrays
29
+ if (Array.isArray(obj)) {
30
+ return obj.map(item => sanitizeObject(item));
31
+ }
32
+ // Handle objects
33
+ const sanitized = {};
34
+ for (const key in obj) {
35
+ // Skip dangerous keys
36
+ if (DANGEROUS_KEYS.includes(key)) {
37
+ continue;
38
+ }
39
+ // Skip inherited properties
40
+ if (!Object.prototype.hasOwnProperty.call(obj, key)) {
41
+ continue;
42
+ }
43
+ // Recursively sanitize nested objects
44
+ const value = obj[key];
45
+ sanitized[key] = sanitizeObject(value);
46
+ }
47
+ return sanitized;
48
+ }
7
49
  /**
8
50
  * Parse JSON string with Zod schema validation
9
51
  */
10
52
  export function parseJson(jsonString, schema) {
11
53
  try {
12
- const data = JSON.parse(jsonString);
54
+ const rawData = JSON.parse(jsonString);
55
+ // SECURITY: Sanitize to prevent prototype pollution (REQ-SEC-005)
56
+ const data = sanitizeObject(rawData);
13
57
  if (schema) {
14
58
  const result = schema.safeParse(data);
15
59
  if (!result.success) {
@@ -169,4 +213,14 @@ export function parseJsonFileWithFallback(filePath, fallback, schema) {
169
213
  const result = parseJsonFile(filePath, schema);
170
214
  return result.success ? result.data : fallback;
171
215
  }
216
+ /**
217
+ * Sanitize an object to prevent prototype pollution
218
+ * Exported for testing purposes
219
+ *
220
+ * @param obj - Object to sanitize
221
+ * @returns Sanitized object
222
+ */
223
+ export function sanitizeJson(obj) {
224
+ return sanitizeObject(obj);
225
+ }
172
226
  //# sourceMappingURL=json-utils.js.map