@dollhousemcp/mcp-server 1.7.2 → 1.7.4
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 +22 -0
- package/README.md.backup +0 -8
- package/dist/auth/GitHubAuthManager.js +2 -2
- package/dist/config/ConfigManager.d.ts +158 -25
- package/dist/config/ConfigManager.d.ts.map +1 -1
- package/dist/config/ConfigManager.js +627 -88
- package/dist/config/ConfigWizard.d.ts +78 -0
- package/dist/config/ConfigWizard.d.ts.map +1 -0
- package/dist/config/ConfigWizard.js +370 -0
- package/dist/config/ConfigWizardCheck.d.ts +47 -0
- package/dist/config/ConfigWizardCheck.d.ts.map +1 -0
- package/dist/config/ConfigWizardCheck.js +208 -0
- package/dist/config/ConfigWizardDisplay.d.ts +64 -0
- package/dist/config/ConfigWizardDisplay.d.ts.map +1 -0
- package/dist/config/ConfigWizardDisplay.js +150 -0
- package/dist/config/WizardFirstResponse.d.ts +25 -0
- package/dist/config/WizardFirstResponse.d.ts.map +1 -0
- package/dist/config/WizardFirstResponse.js +118 -0
- package/dist/config/portfolioConfig.d.ts +40 -0
- package/dist/config/portfolioConfig.d.ts.map +1 -0
- package/dist/config/portfolioConfig.js +58 -0
- package/dist/config/wizardTemplates.d.ts +84 -0
- package/dist/config/wizardTemplates.d.ts.map +1 -0
- package/dist/config/wizardTemplates.js +195 -0
- package/dist/elements/BaseElement.d.ts +15 -0
- package/dist/elements/BaseElement.d.ts.map +1 -1
- package/dist/elements/BaseElement.js +38 -5
- package/dist/generated/version.d.ts +2 -2
- package/dist/generated/version.js +3 -3
- package/dist/handlers/ConfigHandler.d.ts +32 -0
- package/dist/handlers/ConfigHandler.d.ts.map +1 -0
- package/dist/handlers/ConfigHandler.js +202 -0
- package/dist/handlers/PortfolioPullHandler.d.ts +69 -0
- package/dist/handlers/PortfolioPullHandler.d.ts.map +1 -0
- package/dist/handlers/PortfolioPullHandler.js +340 -0
- package/dist/handlers/SyncHandlerV2.d.ts +42 -0
- package/dist/handlers/SyncHandlerV2.d.ts.map +1 -0
- package/dist/handlers/SyncHandlerV2.js +231 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -3
- package/dist/portfolio/GitHubPortfolioIndexer.d.ts +0 -1
- package/dist/portfolio/GitHubPortfolioIndexer.d.ts.map +1 -1
- package/dist/portfolio/GitHubPortfolioIndexer.js +36 -16
- package/dist/portfolio/PortfolioRepoManager.d.ts +2 -1
- package/dist/portfolio/PortfolioRepoManager.d.ts.map +1 -1
- package/dist/portfolio/PortfolioRepoManager.js +2 -1
- package/dist/portfolio/PortfolioSyncManager.d.ts +127 -0
- package/dist/portfolio/PortfolioSyncManager.d.ts.map +1 -0
- package/dist/portfolio/PortfolioSyncManager.js +818 -0
- package/dist/scripts/scripts/run-config-wizard.js +57 -0
- package/dist/scripts/src/config/ConfigManager.js +799 -0
- package/dist/scripts/src/config/ConfigWizard.js +368 -0
- package/dist/scripts/src/errors/SecurityError.js +47 -0
- package/dist/scripts/src/security/constants.js +28 -0
- package/dist/scripts/src/security/contentValidator.js +415 -0
- package/dist/scripts/src/security/errors.js +32 -0
- package/dist/scripts/src/security/regexValidator.js +217 -0
- package/dist/scripts/src/security/secureYamlParser.js +272 -0
- package/dist/scripts/src/security/securityMonitor.js +111 -0
- package/dist/scripts/src/security/validators/unicodeValidator.js +315 -0
- package/dist/scripts/src/utils/logger.js +288 -0
- package/dist/security/audit/config/suppressions.d.ts.map +1 -1
- package/dist/security/audit/config/suppressions.js +54 -2
- package/dist/security/secureYamlParser.d.ts +46 -2
- package/dist/security/secureYamlParser.d.ts.map +1 -1
- package/dist/security/secureYamlParser.js +47 -3
- package/dist/server/ServerSetup.d.ts.map +1 -1
- package/dist/server/ServerSetup.js +16 -10
- package/dist/server/tools/ConfigToolsV2.d.ts +10 -0
- package/dist/server/tools/ConfigToolsV2.d.ts.map +1 -0
- package/dist/server/tools/ConfigToolsV2.js +110 -0
- package/dist/server/types.d.ts +2 -0
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/types.js +1 -1
- package/dist/sync/PortfolioDownloader.d.ts +27 -0
- package/dist/sync/PortfolioDownloader.d.ts.map +1 -0
- package/dist/sync/PortfolioDownloader.js +120 -0
- package/dist/sync/PortfolioSyncComparer.d.ts +50 -0
- package/dist/sync/PortfolioSyncComparer.d.ts.map +1 -0
- package/dist/sync/PortfolioSyncComparer.js +158 -0
- package/dist/tools/getWelcomeMessage.d.ts +41 -0
- package/dist/tools/getWelcomeMessage.d.ts.map +1 -0
- package/dist/tools/getWelcomeMessage.js +109 -0
- package/dist/utils/TemplateRenderer.d.ts +63 -0
- package/dist/utils/TemplateRenderer.d.ts.map +1 -0
- package/dist/utils/TemplateRenderer.js +154 -0
- package/package.json +1 -1
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Content Validator for DollhouseMCP
|
|
4
|
+
*
|
|
5
|
+
* Protects against prompt injection attacks in collection personas
|
|
6
|
+
* by detecting and sanitizing malicious content patterns.
|
|
7
|
+
*
|
|
8
|
+
* Security: SEC-001 - Critical vulnerability protection
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.ContentValidator = void 0;
|
|
12
|
+
const errors_js_1 = require("./errors.js");
|
|
13
|
+
const securityMonitor_js_1 = require("./securityMonitor.js");
|
|
14
|
+
const regexValidator_js_1 = require("./regexValidator.js");
|
|
15
|
+
const constants_js_1 = require("./constants.js");
|
|
16
|
+
const unicodeValidator_js_1 = require("./validators/unicodeValidator.js");
|
|
17
|
+
class ContentValidator {
|
|
18
|
+
/**
|
|
19
|
+
* Validates and sanitizes persona content for security threats
|
|
20
|
+
*/
|
|
21
|
+
static validateAndSanitize(content) {
|
|
22
|
+
// Length validation before pattern matching
|
|
23
|
+
if (content.length > constants_js_1.SECURITY_LIMITS.MAX_CONTENT_LENGTH) {
|
|
24
|
+
throw new errors_js_1.SecurityError(`Content exceeds maximum length of ${constants_js_1.SECURITY_LIMITS.MAX_CONTENT_LENGTH} characters (${content.length} provided)`);
|
|
25
|
+
}
|
|
26
|
+
const detectedPatterns = [];
|
|
27
|
+
let sanitized = content;
|
|
28
|
+
let highestSeverity = 'low';
|
|
29
|
+
// Unicode normalization preprocessing to prevent bypass attacks
|
|
30
|
+
const unicodeResult = unicodeValidator_js_1.UnicodeValidator.normalize(sanitized);
|
|
31
|
+
sanitized = unicodeResult.normalizedContent;
|
|
32
|
+
if (!unicodeResult.isValid && unicodeResult.detectedIssues) {
|
|
33
|
+
detectedPatterns.push(...unicodeResult.detectedIssues.map(issue => `Unicode: ${issue}`));
|
|
34
|
+
if (unicodeResult.severity) {
|
|
35
|
+
highestSeverity = unicodeResult.severity;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Check for injection patterns
|
|
39
|
+
for (const { pattern, severity, description } of this.INJECTION_PATTERNS) {
|
|
40
|
+
// These are trusted internal patterns, so we disable ReDoS rejection
|
|
41
|
+
if (regexValidator_js_1.RegexValidator.validate(content, pattern, {
|
|
42
|
+
maxLength: 50000,
|
|
43
|
+
rejectDangerousPatterns: false,
|
|
44
|
+
logEvents: false // Don't log our own security patterns as dangerous
|
|
45
|
+
})) {
|
|
46
|
+
detectedPatterns.push(description);
|
|
47
|
+
// Update highest severity
|
|
48
|
+
if (severity === 'critical' || (severity === 'high' && highestSeverity !== 'critical')) {
|
|
49
|
+
highestSeverity = severity;
|
|
50
|
+
}
|
|
51
|
+
// Log security event
|
|
52
|
+
securityMonitor_js_1.SecurityMonitor.logSecurityEvent({
|
|
53
|
+
type: 'CONTENT_INJECTION_ATTEMPT',
|
|
54
|
+
severity: severity.toUpperCase(),
|
|
55
|
+
source: 'content_validation',
|
|
56
|
+
details: `Detected pattern: ${description}`,
|
|
57
|
+
});
|
|
58
|
+
// Sanitize by replacing with safe placeholder
|
|
59
|
+
sanitized = sanitized.replace(pattern, '[CONTENT_BLOCKED]');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
isValid: detectedPatterns.length === 0,
|
|
64
|
+
sanitizedContent: sanitized,
|
|
65
|
+
detectedPatterns,
|
|
66
|
+
severity: highestSeverity
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Validates YAML frontmatter for malicious content
|
|
71
|
+
* SECURITY FIX #364: Added YAML bomb detection to prevent denial of service
|
|
72
|
+
*/
|
|
73
|
+
static validateYamlContent(yamlContent) {
|
|
74
|
+
// Length validation before pattern matching
|
|
75
|
+
if (yamlContent.length > constants_js_1.SECURITY_LIMITS.MAX_YAML_LENGTH) {
|
|
76
|
+
securityMonitor_js_1.SecurityMonitor.logSecurityEvent({
|
|
77
|
+
type: 'YAML_INJECTION_ATTEMPT',
|
|
78
|
+
severity: 'HIGH',
|
|
79
|
+
source: 'yaml_validation',
|
|
80
|
+
details: `YAML content exceeds maximum length: ${yamlContent.length} > ${constants_js_1.SECURITY_LIMITS.MAX_YAML_LENGTH}`
|
|
81
|
+
});
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
// SECURITY FIX #364: Check for YAML bombs before other validation
|
|
85
|
+
// SECURITY FIX (PR #552 review): Use RegexValidator for ReDoS protection
|
|
86
|
+
for (const pattern of this.YAML_BOMB_PATTERNS) {
|
|
87
|
+
// Use RegexValidator to safely check patterns with timeout protection
|
|
88
|
+
// This prevents ReDoS attacks from maliciously crafted YAML
|
|
89
|
+
const isMatch = regexValidator_js_1.RegexValidator.validate(yamlContent, pattern, {
|
|
90
|
+
maxLength: constants_js_1.SECURITY_LIMITS.MAX_YAML_LENGTH,
|
|
91
|
+
rejectDangerousPatterns: false, // Our patterns are trusted
|
|
92
|
+
logEvents: false // We handle logging ourselves
|
|
93
|
+
});
|
|
94
|
+
if (isMatch) {
|
|
95
|
+
securityMonitor_js_1.SecurityMonitor.logSecurityEvent({
|
|
96
|
+
type: 'YAML_INJECTION_ATTEMPT',
|
|
97
|
+
severity: 'CRITICAL',
|
|
98
|
+
source: 'yaml_bomb_detection',
|
|
99
|
+
details: `YAML bomb pattern detected: ${pattern.source}`,
|
|
100
|
+
metadata: {
|
|
101
|
+
patternType: 'YAML_BOMB',
|
|
102
|
+
contentLength: yamlContent.length
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// SECURITY FIX #364: Count anchor/alias ratio for amplification detection
|
|
109
|
+
const anchorMatches = yamlContent.match(/&\w+/g) || [];
|
|
110
|
+
const aliasMatches = yamlContent.match(/\*\w+/g) || [];
|
|
111
|
+
const amplificationRatio = anchorMatches.length > 0 ? aliasMatches.length / anchorMatches.length : 0;
|
|
112
|
+
if (amplificationRatio > 10) { // More than 10 aliases per anchor is suspicious
|
|
113
|
+
securityMonitor_js_1.SecurityMonitor.logSecurityEvent({
|
|
114
|
+
type: 'YAML_INJECTION_ATTEMPT',
|
|
115
|
+
severity: 'HIGH',
|
|
116
|
+
source: 'yaml_amplification_detection',
|
|
117
|
+
details: `Excessive alias amplification detected: ${aliasMatches.length} aliases for ${anchorMatches.length} anchors (ratio: ${amplificationRatio.toFixed(2)})`,
|
|
118
|
+
metadata: {
|
|
119
|
+
anchors: anchorMatches.length,
|
|
120
|
+
aliases: aliasMatches.length,
|
|
121
|
+
ratio: amplificationRatio
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
// SECURITY FIX #364: Detect circular reference chains
|
|
127
|
+
// SECURITY FIX (PR #552 review): Optimized from O(n²) to O(n) using Set-based lookups
|
|
128
|
+
const anchorRefs = new Map();
|
|
129
|
+
const lines = yamlContent.split('\n');
|
|
130
|
+
// First pass: Build reference map efficiently
|
|
131
|
+
for (let i = 0; i < lines.length; i++) {
|
|
132
|
+
const anchorMatch = lines[i].match(/&(\w+)/);
|
|
133
|
+
if (anchorMatch) {
|
|
134
|
+
const anchorName = anchorMatch[1];
|
|
135
|
+
// Get references in next 5 lines
|
|
136
|
+
const contextEnd = Math.min(i + 5, lines.length);
|
|
137
|
+
const references = new Set();
|
|
138
|
+
for (let j = i; j < contextEnd; j++) {
|
|
139
|
+
const aliasMatches = lines[j].match(/\*(\w+)/g);
|
|
140
|
+
if (aliasMatches) {
|
|
141
|
+
aliasMatches.forEach(alias => {
|
|
142
|
+
references.add(alias.substring(1)); // Remove * prefix
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
anchorRefs.set(anchorName, references);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// Second pass: Check for circular references (O(n) with Set lookups)
|
|
150
|
+
for (const [anchor1, refs1] of anchorRefs) {
|
|
151
|
+
for (const refAnchor of refs1) {
|
|
152
|
+
const refs2 = anchorRefs.get(refAnchor);
|
|
153
|
+
// Check if the referenced anchor references back to the original
|
|
154
|
+
if (refs2 && refs2.has(anchor1)) {
|
|
155
|
+
securityMonitor_js_1.SecurityMonitor.logSecurityEvent({
|
|
156
|
+
type: 'YAML_INJECTION_ATTEMPT',
|
|
157
|
+
severity: 'CRITICAL',
|
|
158
|
+
source: 'yaml_bomb_detection',
|
|
159
|
+
details: `Circular reference chain detected between anchors: &${anchor1} and &${refAnchor}`,
|
|
160
|
+
metadata: {
|
|
161
|
+
patternType: 'CIRCULAR_REFERENCE',
|
|
162
|
+
anchors: [anchor1, refAnchor]
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// Unicode normalization preprocessing for YAML content
|
|
170
|
+
const unicodeResult = unicodeValidator_js_1.UnicodeValidator.normalize(yamlContent);
|
|
171
|
+
const normalizedYaml = unicodeResult.normalizedContent;
|
|
172
|
+
if (!unicodeResult.isValid && unicodeResult.detectedIssues) {
|
|
173
|
+
securityMonitor_js_1.SecurityMonitor.logSecurityEvent({
|
|
174
|
+
type: 'YAML_UNICODE_ATTACK',
|
|
175
|
+
severity: (unicodeResult.severity?.toUpperCase() || 'MEDIUM'),
|
|
176
|
+
source: 'yaml_validation',
|
|
177
|
+
details: `Unicode attack detected in YAML: ${unicodeResult.detectedIssues.join(', ')}`
|
|
178
|
+
});
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
for (const pattern of this.MALICIOUS_YAML_PATTERNS) {
|
|
182
|
+
// These are trusted internal patterns, so we disable ReDoS rejection
|
|
183
|
+
if (regexValidator_js_1.RegexValidator.validate(normalizedYaml, pattern, {
|
|
184
|
+
maxLength: 10000,
|
|
185
|
+
rejectDangerousPatterns: false,
|
|
186
|
+
logEvents: false // Don't log our own security patterns as dangerous
|
|
187
|
+
})) {
|
|
188
|
+
securityMonitor_js_1.SecurityMonitor.logSecurityEvent({
|
|
189
|
+
type: 'YAML_INJECTION_ATTEMPT',
|
|
190
|
+
severity: 'CRITICAL',
|
|
191
|
+
source: 'yaml_validation',
|
|
192
|
+
details: `Malicious YAML pattern detected: ${pattern}`,
|
|
193
|
+
});
|
|
194
|
+
// Early exit on first match for performance
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Validates persona metadata fields
|
|
202
|
+
*/
|
|
203
|
+
static validateMetadata(metadata) {
|
|
204
|
+
const detectedPatterns = [];
|
|
205
|
+
// Check all string fields in metadata
|
|
206
|
+
const checkField = (fieldName, value) => {
|
|
207
|
+
if (typeof value === 'string') {
|
|
208
|
+
// Check field length first
|
|
209
|
+
if (value.length > constants_js_1.SECURITY_LIMITS.MAX_METADATA_FIELD_LENGTH) {
|
|
210
|
+
detectedPatterns.push(`${fieldName}: Field exceeds maximum length of ${constants_js_1.SECURITY_LIMITS.MAX_METADATA_FIELD_LENGTH} characters`);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
const result = this.validateAndSanitize(value);
|
|
214
|
+
if (!result.isValid || result.detectedPatterns?.length) {
|
|
215
|
+
detectedPatterns.push(`${fieldName}: ${result.detectedPatterns?.join(', ')}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
// Validate standard persona fields
|
|
220
|
+
checkField('name', metadata.name);
|
|
221
|
+
checkField('description', metadata.description);
|
|
222
|
+
checkField('category', metadata.category);
|
|
223
|
+
checkField('author', metadata.author);
|
|
224
|
+
// Check any custom fields
|
|
225
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
226
|
+
if (!['name', 'description', 'category', 'author'].includes(key)) {
|
|
227
|
+
checkField(key, value);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return {
|
|
231
|
+
isValid: detectedPatterns.length === 0,
|
|
232
|
+
detectedPatterns,
|
|
233
|
+
severity: detectedPatterns.length > 0 ? 'high' : 'low'
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Sanitizes a complete persona file (frontmatter + content)
|
|
238
|
+
*/
|
|
239
|
+
static sanitizePersonaContent(content) {
|
|
240
|
+
// Extract frontmatter
|
|
241
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
242
|
+
if (!frontmatterMatch) {
|
|
243
|
+
// No frontmatter, just validate content
|
|
244
|
+
const result = this.validateAndSanitize(content);
|
|
245
|
+
if (!result.isValid && result.severity === 'critical') {
|
|
246
|
+
// FIX: Include specific patterns that triggered the rejection for debugging
|
|
247
|
+
const patterns = result.detectedPatterns?.join(', ') || 'unknown patterns';
|
|
248
|
+
throw new errors_js_1.SecurityError(`Critical security threat detected in persona content: ${patterns}`);
|
|
249
|
+
}
|
|
250
|
+
return result.sanitizedContent || content;
|
|
251
|
+
}
|
|
252
|
+
const yamlContent = frontmatterMatch[1];
|
|
253
|
+
const markdownContent = content.substring(frontmatterMatch[0].length);
|
|
254
|
+
// Validate YAML
|
|
255
|
+
if (!this.validateYamlContent(yamlContent)) {
|
|
256
|
+
throw new errors_js_1.SecurityError('Malicious YAML detected in persona frontmatter');
|
|
257
|
+
}
|
|
258
|
+
// Validate markdown content
|
|
259
|
+
const contentResult = this.validateAndSanitize(markdownContent);
|
|
260
|
+
if (!contentResult.isValid && contentResult.severity === 'critical') {
|
|
261
|
+
// FIX: Include specific patterns that triggered the rejection for debugging
|
|
262
|
+
const patterns = contentResult.detectedPatterns?.join(', ') || 'unknown patterns';
|
|
263
|
+
throw new errors_js_1.SecurityError(`Critical security threat detected in persona content: ${patterns}`);
|
|
264
|
+
}
|
|
265
|
+
// Return sanitized content
|
|
266
|
+
return `---\n${yamlContent}\n---${contentResult.sanitizedContent || markdownContent}`;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
exports.ContentValidator = ContentValidator;
|
|
270
|
+
/**
|
|
271
|
+
* Pattern-based detection system for prompt injection attacks.
|
|
272
|
+
*
|
|
273
|
+
* This approach was chosen over AI-based detection because:
|
|
274
|
+
* 1. Pattern matching cannot be socially engineered or confused
|
|
275
|
+
* 2. Deterministic results ensure consistent security
|
|
276
|
+
* 3. No additional API calls or latency
|
|
277
|
+
* 4. Can't be bypassed by clever prompt engineering
|
|
278
|
+
*
|
|
279
|
+
* The patterns below represent known attack vectors from security research
|
|
280
|
+
* and real-world exploit attempts against AI systems.
|
|
281
|
+
*/
|
|
282
|
+
// Prompt injection patterns that could compromise AI assistants
|
|
283
|
+
ContentValidator.INJECTION_PATTERNS = [
|
|
284
|
+
// System prompt override attempts
|
|
285
|
+
{ pattern: /\[SYSTEM:\s*.*?\]/gi, severity: 'critical', description: 'System prompt override' },
|
|
286
|
+
{ pattern: /\[ADMIN:\s*.*?\]/gi, severity: 'critical', description: 'Admin prompt override' },
|
|
287
|
+
{ pattern: /\[ASSISTANT:\s*.*?\]/gi, severity: 'critical', description: 'Assistant prompt override' },
|
|
288
|
+
{ pattern: /\[USER:\s*.*?\]/gi, severity: 'high', description: 'User prompt override' },
|
|
289
|
+
// Instruction manipulation
|
|
290
|
+
{ pattern: /ignore\s+(all\s+)?previous\s+instructions/gi, severity: 'critical', description: 'Instruction override' },
|
|
291
|
+
{ pattern: /ignore\s+(all\s+)?prior\s+instructions/gi, severity: 'critical', description: 'Instruction override' },
|
|
292
|
+
{ pattern: /disregard\s+(all\s+)?previous\s+instructions/gi, severity: 'critical', description: 'Instruction override' },
|
|
293
|
+
{ pattern: /forget\s+(all\s+)?previous\s+instructions/gi, severity: 'critical', description: 'Instruction override' },
|
|
294
|
+
{ pattern: /you\s+are\s+now\s+(admin|root|system|sudo)/gi, severity: 'critical', description: 'Role elevation attempt' },
|
|
295
|
+
{ pattern: /act\s+as\s+(admin|root|system|sudo)/gi, severity: 'critical', description: 'Role elevation attempt' },
|
|
296
|
+
// Data exfiltration attempts
|
|
297
|
+
{ pattern: /export\s+all\s+(files|data|personas|tokens|credentials)/gi, severity: 'critical', description: 'Data exfiltration' },
|
|
298
|
+
{ pattern: /send\s+all\s+(files|data|personas|tokens|credentials)\s+to/gi, severity: 'critical', description: 'Data exfiltration' },
|
|
299
|
+
{ pattern: /list\s+all\s+(files|tokens|credentials|secrets)/gi, severity: 'high', description: 'Information disclosure' },
|
|
300
|
+
{ pattern: /show\s+me\s+all\s+(tokens|credentials|secrets|api\s+keys)/gi, severity: 'high', description: 'Credential disclosure' },
|
|
301
|
+
// Command execution patterns
|
|
302
|
+
{ pattern: /curl\s+[^\s]+\.(com|net|org|io|dev)/gi, severity: 'critical', description: 'External command execution' },
|
|
303
|
+
{ pattern: /wget\s+[^\s]+\.(com|net|org|io|dev)/gi, severity: 'critical', description: 'External command execution' },
|
|
304
|
+
{ pattern: /\$\([^)]+\)/g, severity: 'critical', description: 'Command substitution' },
|
|
305
|
+
// SECURITY: More refined backtick pattern - distinguishes between dangerous commands and documentation
|
|
306
|
+
// Only block truly dangerous shell commands, not educational examples
|
|
307
|
+
{ pattern: /`[^`]*(?:rm\s+-r[f]?|cat\s+\/etc\/|ls\s+\/etc\/|chmod\s+777|chown\s+root|bash\s+-c\s+[\"']|sh\s+-c\s+[\"']|sudo\s+rm|sudo\s+chmod|passwd\s+|shadow\s+|nc\s+-l|netcat\s+-l|ssh\s+root@)[^`]*`/gi, severity: 'critical', description: 'Dangerous shell command in backticks' },
|
|
308
|
+
// Block actual malicious file operations and network commands with pipes/redirects
|
|
309
|
+
{ pattern: /`[^`]*(?:rm\s+-rf\s+\/|\/etc\/passwd|\/etc\/shadow|\.ssh\/id_|sudo\s+su|>\s*\/dev\/null.*\||curl\s+.*\|\s*sh|wget\s+.*\|\s*bash|bash\s+.*\.sh\s*\|)[^`]*`/gi, severity: 'critical', description: 'Malicious backtick command' },
|
|
310
|
+
// Only block actual script execution, not documentation showing syntax
|
|
311
|
+
{ pattern: /`[^`]*(?:python|perl|ruby|php|node)\s+(?:-e|-c)\s+[\"'](?:import\s+os|exec|eval|system|subprocess)[^`]+`/gi, severity: 'critical', description: 'Malicious script evaluation in backticks' },
|
|
312
|
+
{ pattern: /eval\s*\(/gi, severity: 'critical', description: 'Code evaluation' },
|
|
313
|
+
{ pattern: /exec\s*\(/gi, severity: 'critical', description: 'Code execution' },
|
|
314
|
+
{ pattern: /os\.system\s*\(/gi, severity: 'critical', description: 'System command execution' },
|
|
315
|
+
{ pattern: /subprocess\.(call|run|Popen)/gi, severity: 'critical', description: 'Subprocess execution' },
|
|
316
|
+
// Token/credential patterns
|
|
317
|
+
{ pattern: /GITHUB_TOKEN/gi, severity: 'high', description: 'Token reference' },
|
|
318
|
+
{ pattern: /ghp_[a-zA-Z0-9]{36}/g, severity: 'critical', description: 'GitHub token exposure' },
|
|
319
|
+
{ pattern: /gho_[a-zA-Z0-9]{36}/g, severity: 'critical', description: 'GitHub OAuth token exposure' },
|
|
320
|
+
// Path traversal in content
|
|
321
|
+
{ pattern: /\.\.\/\.\.\/\.\.\//g, severity: 'high', description: 'Path traversal attempt' },
|
|
322
|
+
{ pattern: /\/etc\/passwd/gi, severity: 'high', description: 'Sensitive file access' },
|
|
323
|
+
{ pattern: /\/\.ssh\//gi, severity: 'high', description: 'SSH key access attempt' },
|
|
324
|
+
];
|
|
325
|
+
// Malicious YAML patterns
|
|
326
|
+
// SECURITY FIX #364: YAML bomb detection patterns
|
|
327
|
+
// SECURITY FIX (PR #552 review): Simplified patterns to reduce ReDoS risk
|
|
328
|
+
ContentValidator.YAML_BOMB_PATTERNS = [
|
|
329
|
+
// Detects recursive anchor references that could cause exponential expansion
|
|
330
|
+
// Example: &a [*a] or &bomb ["test", *bomb]
|
|
331
|
+
/&(\w+)\s*\[[^\]]*\*\1[^\]]*\]/, // Direct recursion in array
|
|
332
|
+
/&(\w+)\s*\{[^}]*\*\1[^}]*\}/, // Direct recursion in object
|
|
333
|
+
/^\s*\w+:\s*&(\w+)\s*\n\s*\w+:\s*\*\1/m, // Multi-line value recursion (data: &ref / value: *ref)
|
|
334
|
+
// Simplified pattern to detect deeply nested anchors (less ReDoS risk)
|
|
335
|
+
// Looks for 3+ anchor definitions in close proximity
|
|
336
|
+
/&\w+[^&]*&\w+[^&]*&\w+/, // 3+ anchors (simplified, less backtracking)
|
|
337
|
+
// Detects excessive aliases in close proximity (potential amplification)
|
|
338
|
+
// Example: [*a, *b, *c, *d, *e, *f, *g, *h, *i, *j]
|
|
339
|
+
/\*\w+(?:[,\s]+\*\w+){9,}/, // 10+ aliases in sequence (non-capturing group)
|
|
340
|
+
];
|
|
341
|
+
ContentValidator.MALICIOUS_YAML_PATTERNS = [
|
|
342
|
+
// Language-specific deserialization attacks
|
|
343
|
+
/!!python\/object/,
|
|
344
|
+
/!!python\/module/,
|
|
345
|
+
/!!python\/name/,
|
|
346
|
+
/!!ruby\/object/,
|
|
347
|
+
/!!ruby\/hash/,
|
|
348
|
+
/!!ruby\/struct/,
|
|
349
|
+
/!!ruby\/marshal/,
|
|
350
|
+
/!!java/,
|
|
351
|
+
/!!javax/,
|
|
352
|
+
/!!com\.sun/,
|
|
353
|
+
/!!perl\/hash/,
|
|
354
|
+
/!!perl\/code/,
|
|
355
|
+
/!!php\/object/,
|
|
356
|
+
// Constructor/function injection
|
|
357
|
+
/!!exec/,
|
|
358
|
+
/!!eval/,
|
|
359
|
+
/!!new/,
|
|
360
|
+
/!!construct/,
|
|
361
|
+
/!!apply/,
|
|
362
|
+
/!!call/,
|
|
363
|
+
/!!invoke/,
|
|
364
|
+
// Code execution patterns - more specific to avoid false positives
|
|
365
|
+
/subprocess\./,
|
|
366
|
+
/os\.system/,
|
|
367
|
+
/eval\s*\(/,
|
|
368
|
+
/exec\s*\(/,
|
|
369
|
+
/__import__\s*\(/,
|
|
370
|
+
/require\s*\(/,
|
|
371
|
+
/import\s+(?:os|sys|subprocess|eval|exec)/,
|
|
372
|
+
/include\s+["'].*\.(?:php|sh|py|js|rb)["']/,
|
|
373
|
+
// Command execution variants - more specific patterns
|
|
374
|
+
/popen\s*\(/,
|
|
375
|
+
/spawn\s*\(/,
|
|
376
|
+
/system\s*\(/,
|
|
377
|
+
/backtick\s*\(/,
|
|
378
|
+
/shell_exec\s*\(/,
|
|
379
|
+
/passthru\s*\(/,
|
|
380
|
+
/proc_open\s*\(/,
|
|
381
|
+
// Network operations - require suspicious context
|
|
382
|
+
/socket\.connect/, // Detects socket connection attempts
|
|
383
|
+
/urllib\.request/, // Python HTTP library usage
|
|
384
|
+
/requests\.(?:get|post|put|delete)\s*\(/, // Detects HTTP requests with method calls
|
|
385
|
+
/fetch\s*\(\s*["']https?:\/\//, // Detects fetch calls to external URLs
|
|
386
|
+
/new\s+XMLHttpRequest/, // JavaScript AJAX object creation
|
|
387
|
+
/\.(?:get|post|put|delete)\s*\(\s*["']https?:\/\//, // Method chaining with HTTP requests
|
|
388
|
+
// File system operations - require suspicious context
|
|
389
|
+
/(?:fs\.|file\.|)\s*open\s*\(\s*["'](?:\/etc\/|\/bin\/|\.\.\/)/, // File open with suspicious paths
|
|
390
|
+
/file_get_contents\s*\(/, // PHP file reading function
|
|
391
|
+
/file_put_contents\s*\(/, // PHP file writing function
|
|
392
|
+
/fopen\s*\(\s*["'](?:\/etc\/|\/bin\/|\.\.\/)/, // File open with dangerous system paths
|
|
393
|
+
/(?:fs\.)?\s*readFile\s*\(\s*["'](?:\/etc\/|\/bin\/|\.\.\/)/, // Node.js file read with path traversal
|
|
394
|
+
/(?:fs\.)?\s*writeFile\s*\(\s*["'](?:\/(?:bin|etc|tmp)\/|\.\.\/)/, // Node.js file write to system dirs
|
|
395
|
+
// Protocol handlers
|
|
396
|
+
/file:\/\//,
|
|
397
|
+
/data:\/\//,
|
|
398
|
+
/expect:\/\//,
|
|
399
|
+
/php:\/\//,
|
|
400
|
+
/phar:\/\//,
|
|
401
|
+
/zip:\/\//,
|
|
402
|
+
/ssh2:\/\//,
|
|
403
|
+
/ogg:\/\//,
|
|
404
|
+
// YAML-specific dangerous features
|
|
405
|
+
/&[a-zA-Z0-9_]+\s*!!/, // Anchor with tag combination
|
|
406
|
+
/\*[a-zA-Z0-9_]+\s*!!/, // Alias with tag combination
|
|
407
|
+
/!!merge/,
|
|
408
|
+
/!!binary/,
|
|
409
|
+
/!!timestamp/,
|
|
410
|
+
// Unicode/encoding bypass attempts - prevent visual spoofing attacks
|
|
411
|
+
/\\[uU]0*(?:22|27|60|3[cC])/, // Unicode escapes for quotes (") and brackets (<>)
|
|
412
|
+
/[\u202A-\u202E\u2066-\u2069]/, // Direction override chars (RLO, LRO, isolates)
|
|
413
|
+
/[\u200B-\u200F\u2028-\u202F]/, // Zero-width spaces, line/paragraph separators
|
|
414
|
+
/[\uFEFF\uFFFE\uFFFF]/, // BOM, non-characters for payload hiding
|
|
415
|
+
];
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Security-related error classes
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.TimeoutError = exports.ValidationError = exports.SecurityError = void 0;
|
|
7
|
+
class SecurityError extends Error {
|
|
8
|
+
constructor(message, code) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = 'SecurityError';
|
|
11
|
+
this.code = code;
|
|
12
|
+
// Maintains proper prototype chain for instanceof checks
|
|
13
|
+
Object.setPrototypeOf(this, SecurityError.prototype);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.SecurityError = SecurityError;
|
|
17
|
+
class ValidationError extends Error {
|
|
18
|
+
constructor(message) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.name = 'ValidationError';
|
|
21
|
+
Object.setPrototypeOf(this, ValidationError.prototype);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.ValidationError = ValidationError;
|
|
25
|
+
class TimeoutError extends SecurityError {
|
|
26
|
+
constructor(message = 'Operation timed out') {
|
|
27
|
+
super(message);
|
|
28
|
+
this.name = 'TimeoutError';
|
|
29
|
+
Object.setPrototypeOf(this, TimeoutError.prototype);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.TimeoutError = TimeoutError;
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* RegexValidator - Provides protection against ReDoS attacks
|
|
4
|
+
*
|
|
5
|
+
* This module implements safe regex execution by:
|
|
6
|
+
* 1. Pre-validating content length based on pattern complexity
|
|
7
|
+
* 2. Analyzing patterns for known ReDoS vulnerabilities
|
|
8
|
+
* 3. Limiting execution based on calculated risk
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.RegexValidator = void 0;
|
|
12
|
+
const errors_js_1 = require("./errors.js");
|
|
13
|
+
const securityMonitor_js_1 = require("./securityMonitor.js");
|
|
14
|
+
class RegexValidator {
|
|
15
|
+
/**
|
|
16
|
+
* Validates content against a pattern with ReDoS protection
|
|
17
|
+
*
|
|
18
|
+
* Protection strategy:
|
|
19
|
+
* 1. Analyze pattern complexity
|
|
20
|
+
* 2. Enforce content length limits based on complexity
|
|
21
|
+
* 3. Reject known dangerous patterns
|
|
22
|
+
* 4. Execute regex only if safe
|
|
23
|
+
*/
|
|
24
|
+
static validate(content, pattern, options = {}) {
|
|
25
|
+
const { maxLength, rejectDangerousPatterns = true, logEvents = true } = options;
|
|
26
|
+
// Analyze pattern for ReDoS risks
|
|
27
|
+
const analysis = this.analyzePattern(pattern);
|
|
28
|
+
// Reject dangerous patterns if configured
|
|
29
|
+
if (rejectDangerousPatterns && !analysis.safe) {
|
|
30
|
+
if (logEvents) {
|
|
31
|
+
securityMonitor_js_1.SecurityMonitor.logSecurityEvent({
|
|
32
|
+
type: 'UPDATE_SECURITY_VIOLATION',
|
|
33
|
+
severity: 'HIGH',
|
|
34
|
+
source: 'RegexValidator',
|
|
35
|
+
details: 'Dangerous regex pattern rejected',
|
|
36
|
+
additionalData: {
|
|
37
|
+
pattern: pattern.source,
|
|
38
|
+
risks: analysis.risks
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
throw new errors_js_1.SecurityError(`Pattern rejected due to ReDoS risk: ${analysis.risks.join(', ')}`);
|
|
43
|
+
}
|
|
44
|
+
// Determine effective max length
|
|
45
|
+
const effectiveMaxLength = maxLength ?? analysis.maxSafeLength;
|
|
46
|
+
// Check content length
|
|
47
|
+
if (content.length > effectiveMaxLength) {
|
|
48
|
+
throw new errors_js_1.SecurityError(`Content too large for validation: ${content.length} bytes (max: ${effectiveMaxLength} for ${analysis.complexity} complexity pattern)`);
|
|
49
|
+
}
|
|
50
|
+
// Create a copy of the regex to avoid modifying the original
|
|
51
|
+
const safeCopy = new RegExp(pattern.source, pattern.flags);
|
|
52
|
+
try {
|
|
53
|
+
// Track execution time for monitoring
|
|
54
|
+
const startTime = performance.now();
|
|
55
|
+
const result = safeCopy.test(content);
|
|
56
|
+
const elapsed = performance.now() - startTime;
|
|
57
|
+
// Log slow patterns
|
|
58
|
+
if (elapsed > 50 && logEvents) {
|
|
59
|
+
securityMonitor_js_1.SecurityMonitor.logSecurityEvent({
|
|
60
|
+
type: 'RATE_LIMIT_WARNING',
|
|
61
|
+
severity: 'MEDIUM',
|
|
62
|
+
source: 'RegexValidator',
|
|
63
|
+
details: `Slow regex execution: ${elapsed.toFixed(2)}ms`,
|
|
64
|
+
additionalData: {
|
|
65
|
+
pattern: pattern.source,
|
|
66
|
+
contentLength: content.length,
|
|
67
|
+
elapsed
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
// Handle any regex errors
|
|
75
|
+
if (logEvents) {
|
|
76
|
+
securityMonitor_js_1.SecurityMonitor.logSecurityEvent({
|
|
77
|
+
type: 'UPDATE_SECURITY_VIOLATION',
|
|
78
|
+
severity: 'HIGH',
|
|
79
|
+
source: 'RegexValidator',
|
|
80
|
+
details: 'Regex execution error',
|
|
81
|
+
additionalData: {
|
|
82
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Validates multiple patterns with shared risk assessment
|
|
91
|
+
*/
|
|
92
|
+
static validateAny(content, patterns, options = {}) {
|
|
93
|
+
for (const pattern of patterns) {
|
|
94
|
+
if (this.validate(content, pattern, options)) {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Validates all patterns must match
|
|
102
|
+
*/
|
|
103
|
+
static validateAll(content, patterns, options = {}) {
|
|
104
|
+
for (const pattern of patterns) {
|
|
105
|
+
if (!this.validate(content, pattern, options)) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Analyzes a regex pattern for potential ReDoS vulnerabilities
|
|
113
|
+
*
|
|
114
|
+
* Detects patterns known to cause exponential backtracking:
|
|
115
|
+
* - Nested quantifiers: (a+)+, (a*)*
|
|
116
|
+
* - Alternation with overlap: (a|a)*
|
|
117
|
+
* - Quantified groups with alternation: (a|b)+
|
|
118
|
+
* - Catastrophic patterns: (.+)+$
|
|
119
|
+
*/
|
|
120
|
+
static analyzePattern(pattern) {
|
|
121
|
+
const source = pattern.source;
|
|
122
|
+
const risks = [];
|
|
123
|
+
// Nested quantifiers - extremely dangerous
|
|
124
|
+
if (/\([^)]+[+*]\)[+*]/.test(source) ||
|
|
125
|
+
/\([^)]+\{[^}]+\}\)[+*]/.test(source) ||
|
|
126
|
+
/\(\w+[+*]\)[+*]/.test(source)) {
|
|
127
|
+
risks.push('Nested quantifiers detected');
|
|
128
|
+
}
|
|
129
|
+
// Alternation with repetition
|
|
130
|
+
if (/\([^)]*\|[^)]*\)[+*]/.test(source)) {
|
|
131
|
+
risks.push('Quantified alternation detected');
|
|
132
|
+
}
|
|
133
|
+
// Alternation with overlap (e.g., (a|a)*)
|
|
134
|
+
const alternationMatch = source.match(/\(([^|)]+)\|([^)]+)\)/g);
|
|
135
|
+
if (alternationMatch) {
|
|
136
|
+
for (const match of alternationMatch) {
|
|
137
|
+
const parts = match.slice(1, -1).split('|');
|
|
138
|
+
if (parts.some((part, i) => parts.slice(i + 1).includes(part))) {
|
|
139
|
+
risks.push('Overlapping alternation detected');
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Catastrophic backtracking patterns
|
|
145
|
+
// Check for patterns like (.+)+, (.*)+, etc. that can cause exponential backtracking
|
|
146
|
+
if (/\([^)]*\.\+[^)]*\)\+/.test(source) || /\([^)]*\.\*[^)]*\)\+/.test(source) || /\([^)]*\\w\+[^)]*\)\+/.test(source)) {
|
|
147
|
+
risks.push('Potential catastrophic backtracking');
|
|
148
|
+
}
|
|
149
|
+
// Unbounded lookahead/lookbehind with quantifiers
|
|
150
|
+
if (/\(\?[=!<].*[+*]/.test(source)) {
|
|
151
|
+
risks.push('Unbounded lookahead/lookbehind');
|
|
152
|
+
}
|
|
153
|
+
// Polynomial patterns (multiple quantifiers in sequence)
|
|
154
|
+
const quantifierCount = (source.match(/[+*?]|\{\d*,?\d*\}/g) || []).length;
|
|
155
|
+
if (quantifierCount > 3) {
|
|
156
|
+
risks.push('Multiple quantifiers detected');
|
|
157
|
+
}
|
|
158
|
+
// Determine complexity and safe content length
|
|
159
|
+
let complexity;
|
|
160
|
+
let maxSafeLength;
|
|
161
|
+
if (risks.length === 0) {
|
|
162
|
+
if (quantifierCount === 0) {
|
|
163
|
+
complexity = 'low';
|
|
164
|
+
maxSafeLength = this.COMPLEXITY_LIMITS.low;
|
|
165
|
+
}
|
|
166
|
+
else if (quantifierCount <= 3) {
|
|
167
|
+
complexity = 'medium';
|
|
168
|
+
maxSafeLength = this.COMPLEXITY_LIMITS.medium;
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
complexity = 'high';
|
|
172
|
+
maxSafeLength = this.COMPLEXITY_LIMITS.high;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else if (risks.length === 1) {
|
|
176
|
+
complexity = 'high';
|
|
177
|
+
maxSafeLength = this.COMPLEXITY_LIMITS.high;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
complexity = 'high';
|
|
181
|
+
maxSafeLength = this.COMPLEXITY_LIMITS.high;
|
|
182
|
+
}
|
|
183
|
+
return {
|
|
184
|
+
safe: risks.length === 0,
|
|
185
|
+
risks,
|
|
186
|
+
complexity,
|
|
187
|
+
maxSafeLength
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Creates a regex pattern with safety analysis
|
|
192
|
+
*/
|
|
193
|
+
static createSafePattern(pattern, flags) {
|
|
194
|
+
const regex = new RegExp(pattern, flags);
|
|
195
|
+
const analysis = this.analyzePattern(regex);
|
|
196
|
+
if (!analysis.safe) {
|
|
197
|
+
securityMonitor_js_1.SecurityMonitor.logSecurityEvent({
|
|
198
|
+
type: 'UPDATE_SECURITY_VIOLATION',
|
|
199
|
+
severity: 'MEDIUM',
|
|
200
|
+
source: 'RegexValidator',
|
|
201
|
+
details: 'Potentially dangerous regex pattern created',
|
|
202
|
+
additionalData: {
|
|
203
|
+
pattern,
|
|
204
|
+
risks: analysis.risks
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
return regex;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
exports.RegexValidator = RegexValidator;
|
|
212
|
+
// Default limits based on pattern complexity
|
|
213
|
+
RegexValidator.COMPLEXITY_LIMITS = {
|
|
214
|
+
low: 100000, // 100KB for simple patterns
|
|
215
|
+
medium: 10000, // 10KB for moderate patterns
|
|
216
|
+
high: 1000 // 1KB for complex patterns
|
|
217
|
+
};
|