mcp-wordpress 2.2.0 → 2.3.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.
- package/dist/security/AISecurityScanner.d.ts +175 -0
- package/dist/security/AISecurityScanner.d.ts.map +1 -0
- package/dist/security/AISecurityScanner.js +645 -0
- package/dist/security/AISecurityScanner.js.map +1 -0
- package/dist/security/AutomatedRemediation.d.ts +145 -0
- package/dist/security/AutomatedRemediation.d.ts.map +1 -0
- package/dist/security/AutomatedRemediation.js +535 -0
- package/dist/security/AutomatedRemediation.js.map +1 -0
- package/dist/security/SecurityCIPipeline.d.ts +213 -0
- package/dist/security/SecurityCIPipeline.d.ts.map +1 -0
- package/dist/security/SecurityCIPipeline.js +684 -0
- package/dist/security/SecurityCIPipeline.js.map +1 -0
- package/dist/security/SecurityConfigManager.d.ts +294 -0
- package/dist/security/SecurityConfigManager.d.ts.map +1 -0
- package/dist/security/SecurityConfigManager.js +553 -0
- package/dist/security/SecurityConfigManager.js.map +1 -0
- package/dist/security/SecurityMonitoring.d.ts +245 -0
- package/dist/security/SecurityMonitoring.d.ts.map +1 -0
- package/dist/security/SecurityMonitoring.js +596 -0
- package/dist/security/SecurityMonitoring.js.map +1 -0
- package/dist/security/SecurityReviewer.d.ts +168 -0
- package/dist/security/SecurityReviewer.d.ts.map +1 -0
- package/dist/security/SecurityReviewer.js +683 -0
- package/dist/security/SecurityReviewer.js.map +1 -0
- package/dist/security/index.d.ts +182 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +189 -0
- package/dist/security/index.js.map +1 -0
- package/package.json +8 -3
- package/src/security/AISecurityScanner.ts +780 -0
- package/src/security/AutomatedRemediation.ts +665 -0
- package/src/security/SecurityCIPipeline.ts +969 -0
- package/src/security/SecurityConfigManager.ts +829 -0
- package/src/security/SecurityMonitoring.ts +841 -0
- package/src/security/SecurityReviewer.ts +855 -0
- package/src/security/index.ts +249 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Automated Security Remediation System
|
|
3
|
+
* Provides intelligent automated fixes for detected vulnerabilities
|
|
4
|
+
*/
|
|
5
|
+
import { SecurityVulnerability, SecurityScanResult } from "./AISecurityScanner";
|
|
6
|
+
interface RemediationAction {
|
|
7
|
+
id: string;
|
|
8
|
+
type: "replace" | "insert" | "delete" | "config" | "file";
|
|
9
|
+
target: {
|
|
10
|
+
file?: string | undefined;
|
|
11
|
+
line?: number | undefined;
|
|
12
|
+
pattern?: RegExp | undefined;
|
|
13
|
+
value?: string | undefined;
|
|
14
|
+
};
|
|
15
|
+
replacement: {
|
|
16
|
+
content?: string;
|
|
17
|
+
config?: Record<string, any>;
|
|
18
|
+
action?: string;
|
|
19
|
+
};
|
|
20
|
+
backup: {
|
|
21
|
+
enabled: boolean;
|
|
22
|
+
path?: string;
|
|
23
|
+
};
|
|
24
|
+
validation: {
|
|
25
|
+
test?: string;
|
|
26
|
+
expected?: any;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export interface RemediationResult {
|
|
30
|
+
vulnerabilityId: string;
|
|
31
|
+
success: boolean;
|
|
32
|
+
action: string;
|
|
33
|
+
details: string;
|
|
34
|
+
timestamp: Date;
|
|
35
|
+
backupPath?: string | undefined;
|
|
36
|
+
validationResult?: boolean | undefined;
|
|
37
|
+
}
|
|
38
|
+
interface RemediationPlan {
|
|
39
|
+
planId: string;
|
|
40
|
+
vulnerabilities: SecurityVulnerability[];
|
|
41
|
+
actions: RemediationAction[];
|
|
42
|
+
estimatedDuration: number;
|
|
43
|
+
riskLevel: "low" | "medium" | "high";
|
|
44
|
+
requiresApproval: boolean;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Automated Security Remediation Engine
|
|
48
|
+
*/
|
|
49
|
+
export declare class AutomatedRemediation {
|
|
50
|
+
private remediationHistory;
|
|
51
|
+
private backupDirectory;
|
|
52
|
+
/**
|
|
53
|
+
* Create remediation plan for scan results
|
|
54
|
+
*/
|
|
55
|
+
createRemediationPlan(scanResult: SecurityScanResult): Promise<RemediationPlan>;
|
|
56
|
+
/**
|
|
57
|
+
* Create remediation action for a specific vulnerability
|
|
58
|
+
*/
|
|
59
|
+
private createRemediationAction;
|
|
60
|
+
/**
|
|
61
|
+
* Create SQL injection remediation
|
|
62
|
+
*/
|
|
63
|
+
private createSQLInjectionRemediation;
|
|
64
|
+
/**
|
|
65
|
+
* Create XSS remediation
|
|
66
|
+
*/
|
|
67
|
+
private createXSSRemediation;
|
|
68
|
+
/**
|
|
69
|
+
* Create path traversal remediation
|
|
70
|
+
*/
|
|
71
|
+
private createPathTraversalRemediation;
|
|
72
|
+
/**
|
|
73
|
+
* Create credential exposure remediation
|
|
74
|
+
*/
|
|
75
|
+
private createCredentialExposureRemediation;
|
|
76
|
+
/**
|
|
77
|
+
* Create configuration remediation
|
|
78
|
+
*/
|
|
79
|
+
private createConfigRemediation;
|
|
80
|
+
/**
|
|
81
|
+
* Create information disclosure remediation
|
|
82
|
+
*/
|
|
83
|
+
private createInfoDisclosureRemediation;
|
|
84
|
+
/**
|
|
85
|
+
* Execute remediation plan
|
|
86
|
+
*/
|
|
87
|
+
executeRemediationPlan(plan: RemediationPlan, options?: {
|
|
88
|
+
dryRun?: boolean;
|
|
89
|
+
requireConfirmation?: boolean;
|
|
90
|
+
}): Promise<RemediationResult[]>;
|
|
91
|
+
/**
|
|
92
|
+
* Execute a single remediation action
|
|
93
|
+
*/
|
|
94
|
+
private executeRemediationAction;
|
|
95
|
+
/**
|
|
96
|
+
* Execute replace action
|
|
97
|
+
*/
|
|
98
|
+
private executeReplaceAction;
|
|
99
|
+
/**
|
|
100
|
+
* Execute insert action
|
|
101
|
+
*/
|
|
102
|
+
private executeInsertAction;
|
|
103
|
+
/**
|
|
104
|
+
* Execute delete action
|
|
105
|
+
*/
|
|
106
|
+
private executeDeleteAction;
|
|
107
|
+
/**
|
|
108
|
+
* Execute config action
|
|
109
|
+
*/
|
|
110
|
+
private executeConfigAction;
|
|
111
|
+
/**
|
|
112
|
+
* Execute file action
|
|
113
|
+
*/
|
|
114
|
+
private executeFileAction;
|
|
115
|
+
/**
|
|
116
|
+
* Create backup of file
|
|
117
|
+
*/
|
|
118
|
+
private createBackup;
|
|
119
|
+
/**
|
|
120
|
+
* Ensure backup directory exists
|
|
121
|
+
*/
|
|
122
|
+
private ensureBackupDirectory;
|
|
123
|
+
/**
|
|
124
|
+
* Validate remediation
|
|
125
|
+
*/
|
|
126
|
+
private validateRemediation;
|
|
127
|
+
/**
|
|
128
|
+
* Simulate remediation actions for dry run
|
|
129
|
+
*/
|
|
130
|
+
private simulateRemediationActions;
|
|
131
|
+
/**
|
|
132
|
+
* Get remediation history
|
|
133
|
+
*/
|
|
134
|
+
getRemediationHistory(): RemediationResult[];
|
|
135
|
+
/**
|
|
136
|
+
* Rollback remediation using backup
|
|
137
|
+
*/
|
|
138
|
+
rollbackRemediation(backupPath: string, targetFile: string): Promise<void>;
|
|
139
|
+
/**
|
|
140
|
+
* Clean up old backups
|
|
141
|
+
*/
|
|
142
|
+
cleanupBackups(maxAge?: number): Promise<void>;
|
|
143
|
+
}
|
|
144
|
+
export {};
|
|
145
|
+
//# sourceMappingURL=AutomatedRemediation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AutomatedRemediation.d.ts","sourceRoot":"","sources":["../../src/security/AutomatedRemediation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Automated Security Remediation System
|
|
3
|
+
* Provides intelligent automated fixes for detected vulnerabilities
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from "fs/promises";
|
|
6
|
+
import * as path from "path";
|
|
7
|
+
import { SecurityUtils } from "./SecurityConfig";
|
|
8
|
+
import { SecurityValidationError } from "./InputValidator";
|
|
9
|
+
/**
|
|
10
|
+
* Automated remediation patterns for common vulnerabilities
|
|
11
|
+
*/
|
|
12
|
+
const REMEDIATION_PATTERNS = {
|
|
13
|
+
sqlInjection: {
|
|
14
|
+
pattern: /(SELECT|INSERT|UPDATE|DELETE).*?[\'\"].*?[\'\"].*?(WHERE|FROM|INTO)/gi,
|
|
15
|
+
replacement: "// TODO: Replace with parameterized query",
|
|
16
|
+
confidence: 0.7,
|
|
17
|
+
},
|
|
18
|
+
xssSimple: {
|
|
19
|
+
pattern: /innerHTML\s*=\s*[^;]+;?/gi,
|
|
20
|
+
replacement: "textContent = $1; // XSS remediation",
|
|
21
|
+
confidence: 0.8,
|
|
22
|
+
},
|
|
23
|
+
pathTraversal: {
|
|
24
|
+
pattern: /\.\.[\/\\]/g,
|
|
25
|
+
replacement: "",
|
|
26
|
+
confidence: 0.9,
|
|
27
|
+
},
|
|
28
|
+
credentialExposure: {
|
|
29
|
+
pattern: /(password|secret|key|token)\s*[:=]\s*['"][^'"]+['"]/gi,
|
|
30
|
+
replacement: "$1 = process.env.$1?.toUpperCase() || '[REQUIRED]'",
|
|
31
|
+
confidence: 0.85,
|
|
32
|
+
},
|
|
33
|
+
httpToHttps: {
|
|
34
|
+
pattern: /http:\/\//gi,
|
|
35
|
+
replacement: "https://",
|
|
36
|
+
confidence: 0.95,
|
|
37
|
+
},
|
|
38
|
+
insecureConfig: {
|
|
39
|
+
pattern: /(ssl|secure|verify)\s*[:=]\s*false/gi,
|
|
40
|
+
replacement: "$1: true",
|
|
41
|
+
confidence: 0.9,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Automated Security Remediation Engine
|
|
46
|
+
*/
|
|
47
|
+
export class AutomatedRemediation {
|
|
48
|
+
remediationHistory = [];
|
|
49
|
+
backupDirectory = "security-backups";
|
|
50
|
+
/**
|
|
51
|
+
* Create remediation plan for scan results
|
|
52
|
+
*/
|
|
53
|
+
async createRemediationPlan(scanResult) {
|
|
54
|
+
const planId = SecurityUtils.generateSecureToken(16);
|
|
55
|
+
const remediableVulns = scanResult.vulnerabilities.filter((v) => v.remediation.automated);
|
|
56
|
+
console.log(`[Remediation] Creating plan for ${remediableVulns.length} remediable vulnerabilities`);
|
|
57
|
+
const actions = [];
|
|
58
|
+
let estimatedDuration = 0;
|
|
59
|
+
let maxRiskLevel = "low";
|
|
60
|
+
for (const vulnerability of remediableVulns) {
|
|
61
|
+
const action = await this.createRemediationAction(vulnerability);
|
|
62
|
+
if (action) {
|
|
63
|
+
actions.push(action);
|
|
64
|
+
estimatedDuration += 30; // 30 seconds per action estimate
|
|
65
|
+
// Update risk level
|
|
66
|
+
if (vulnerability.severity === "critical" || vulnerability.severity === "high") {
|
|
67
|
+
maxRiskLevel = "high";
|
|
68
|
+
}
|
|
69
|
+
else if (vulnerability.severity === "medium" && maxRiskLevel === "low") {
|
|
70
|
+
maxRiskLevel = "medium";
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const requiresApproval = maxRiskLevel === "high" || actions.length > 10;
|
|
75
|
+
return {
|
|
76
|
+
planId,
|
|
77
|
+
vulnerabilities: remediableVulns,
|
|
78
|
+
actions,
|
|
79
|
+
estimatedDuration,
|
|
80
|
+
riskLevel: maxRiskLevel,
|
|
81
|
+
requiresApproval,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Create remediation action for a specific vulnerability
|
|
86
|
+
*/
|
|
87
|
+
async createRemediationAction(vulnerability) {
|
|
88
|
+
const actionId = SecurityUtils.generateSecureToken(12);
|
|
89
|
+
switch (vulnerability.type) {
|
|
90
|
+
case "SQL Injection":
|
|
91
|
+
return this.createSQLInjectionRemediation(actionId, vulnerability);
|
|
92
|
+
case "Cross-Site Scripting (XSS)":
|
|
93
|
+
return this.createXSSRemediation(actionId, vulnerability);
|
|
94
|
+
case "Path Traversal":
|
|
95
|
+
return this.createPathTraversalRemediation(actionId, vulnerability);
|
|
96
|
+
case "Credential Exposure":
|
|
97
|
+
return this.createCredentialExposureRemediation(actionId, vulnerability);
|
|
98
|
+
case "Insecure Configuration":
|
|
99
|
+
return this.createConfigRemediation(actionId, vulnerability);
|
|
100
|
+
case "Information Disclosure":
|
|
101
|
+
return this.createInfoDisclosureRemediation(actionId, vulnerability);
|
|
102
|
+
default:
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Create SQL injection remediation
|
|
108
|
+
*/
|
|
109
|
+
createSQLInjectionRemediation(actionId, vulnerability) {
|
|
110
|
+
return {
|
|
111
|
+
id: actionId,
|
|
112
|
+
type: "replace",
|
|
113
|
+
target: {
|
|
114
|
+
file: vulnerability.location.file,
|
|
115
|
+
line: vulnerability.location.line,
|
|
116
|
+
pattern: REMEDIATION_PATTERNS.sqlInjection.pattern,
|
|
117
|
+
},
|
|
118
|
+
replacement: {
|
|
119
|
+
content: "// SECURITY FIX: Replace with parameterized query to prevent SQL injection\n" +
|
|
120
|
+
"// Example: db.query('SELECT * FROM users WHERE id = ?', [userId])",
|
|
121
|
+
},
|
|
122
|
+
backup: {
|
|
123
|
+
enabled: true,
|
|
124
|
+
},
|
|
125
|
+
validation: {
|
|
126
|
+
test: 'grep -n "SELECT.*WHERE" $file | wc -l',
|
|
127
|
+
expected: 0,
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Create XSS remediation
|
|
133
|
+
*/
|
|
134
|
+
createXSSRemediation(actionId, vulnerability) {
|
|
135
|
+
return {
|
|
136
|
+
id: actionId,
|
|
137
|
+
type: "replace",
|
|
138
|
+
target: {
|
|
139
|
+
file: vulnerability.location.file,
|
|
140
|
+
line: vulnerability.location.line,
|
|
141
|
+
pattern: /innerHTML\s*=\s*([^;]+);?/gi,
|
|
142
|
+
},
|
|
143
|
+
replacement: {
|
|
144
|
+
content: "textContent = $1; // XSS remediation: use textContent instead of innerHTML",
|
|
145
|
+
},
|
|
146
|
+
backup: {
|
|
147
|
+
enabled: true,
|
|
148
|
+
},
|
|
149
|
+
validation: {
|
|
150
|
+
test: 'grep -n "innerHTML" $file | wc -l',
|
|
151
|
+
expected: 0,
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Create path traversal remediation
|
|
157
|
+
*/
|
|
158
|
+
createPathTraversalRemediation(actionId, vulnerability) {
|
|
159
|
+
return {
|
|
160
|
+
id: actionId,
|
|
161
|
+
type: "replace",
|
|
162
|
+
target: {
|
|
163
|
+
file: vulnerability.location.file,
|
|
164
|
+
line: vulnerability.location.line,
|
|
165
|
+
pattern: /\.\.[\/\\]/g,
|
|
166
|
+
},
|
|
167
|
+
replacement: {
|
|
168
|
+
content: "", // Remove path traversal sequences
|
|
169
|
+
},
|
|
170
|
+
backup: {
|
|
171
|
+
enabled: true,
|
|
172
|
+
},
|
|
173
|
+
validation: {
|
|
174
|
+
test: 'grep -n "\\.\\./" $file | wc -l',
|
|
175
|
+
expected: 0,
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Create credential exposure remediation
|
|
181
|
+
*/
|
|
182
|
+
createCredentialExposureRemediation(actionId, vulnerability) {
|
|
183
|
+
return {
|
|
184
|
+
id: actionId,
|
|
185
|
+
type: "replace",
|
|
186
|
+
target: {
|
|
187
|
+
file: vulnerability.location.file,
|
|
188
|
+
line: vulnerability.location.line,
|
|
189
|
+
pattern: /(password|secret|key|token)\s*[:=]\s*['"][^'"]+['"]/gi,
|
|
190
|
+
},
|
|
191
|
+
replacement: {
|
|
192
|
+
content: "// SECURITY FIX: Credential moved to environment variable\n" +
|
|
193
|
+
"// Add to .env: $1=your_actual_value\n" +
|
|
194
|
+
"$1: process.env.$1 || (() => { throw new Error('$1 environment variable required'); })()",
|
|
195
|
+
},
|
|
196
|
+
backup: {
|
|
197
|
+
enabled: true,
|
|
198
|
+
},
|
|
199
|
+
validation: {
|
|
200
|
+
test: 'grep -n "password.*=.*[\'\\"]" $file | wc -l',
|
|
201
|
+
expected: 0,
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Create configuration remediation
|
|
207
|
+
*/
|
|
208
|
+
createConfigRemediation(actionId, vulnerability) {
|
|
209
|
+
return {
|
|
210
|
+
id: actionId,
|
|
211
|
+
type: "replace",
|
|
212
|
+
target: {
|
|
213
|
+
file: vulnerability.location.file,
|
|
214
|
+
line: vulnerability.location.line,
|
|
215
|
+
pattern: /(ssl|secure|verify)\s*[:=]\s*false/gi,
|
|
216
|
+
},
|
|
217
|
+
replacement: {
|
|
218
|
+
content: "$1: true // Security fix: enabled secure configuration",
|
|
219
|
+
},
|
|
220
|
+
backup: {
|
|
221
|
+
enabled: true,
|
|
222
|
+
},
|
|
223
|
+
validation: {
|
|
224
|
+
test: 'grep -n "ssl.*false" $file | wc -l',
|
|
225
|
+
expected: 0,
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Create information disclosure remediation
|
|
231
|
+
*/
|
|
232
|
+
createInfoDisclosureRemediation(actionId, vulnerability) {
|
|
233
|
+
return {
|
|
234
|
+
id: actionId,
|
|
235
|
+
type: "replace",
|
|
236
|
+
target: {
|
|
237
|
+
file: vulnerability.location.file,
|
|
238
|
+
line: vulnerability.location.line,
|
|
239
|
+
pattern: /(debug|trace|error)\s*[:=]\s*true/gi,
|
|
240
|
+
},
|
|
241
|
+
replacement: {
|
|
242
|
+
content: "$1: process.env.NODE_ENV !== 'production' // Security fix: disable in production",
|
|
243
|
+
},
|
|
244
|
+
backup: {
|
|
245
|
+
enabled: true,
|
|
246
|
+
},
|
|
247
|
+
validation: {
|
|
248
|
+
test: 'grep -n "debug.*true" $file | wc -l',
|
|
249
|
+
expected: 0,
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Execute remediation plan
|
|
255
|
+
*/
|
|
256
|
+
async executeRemediationPlan(plan, options = {}) {
|
|
257
|
+
console.log(`[Remediation] Executing plan ${plan.planId} with ${plan.actions.length} actions`);
|
|
258
|
+
if (options.dryRun) {
|
|
259
|
+
console.log("[Remediation] DRY RUN MODE - No changes will be made");
|
|
260
|
+
return this.simulateRemediationActions(plan.actions);
|
|
261
|
+
}
|
|
262
|
+
const results = [];
|
|
263
|
+
// Ensure backup directory exists
|
|
264
|
+
await this.ensureBackupDirectory();
|
|
265
|
+
for (const action of plan.actions) {
|
|
266
|
+
try {
|
|
267
|
+
console.log(`[Remediation] Executing action ${action.id} of type ${action.type}`);
|
|
268
|
+
const result = await this.executeRemediationAction(action);
|
|
269
|
+
results.push(result);
|
|
270
|
+
if (!result.success) {
|
|
271
|
+
console.error(`[Remediation] Action ${action.id} failed: ${result.details}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
console.error(`[Remediation] Action ${action.id} threw error:`, error);
|
|
276
|
+
results.push({
|
|
277
|
+
vulnerabilityId: action.id,
|
|
278
|
+
success: false,
|
|
279
|
+
action: action.type,
|
|
280
|
+
details: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
281
|
+
timestamp: new Date(),
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
this.remediationHistory.push(...results);
|
|
286
|
+
const successCount = results.filter((r) => r.success).length;
|
|
287
|
+
console.log(`[Remediation] Plan completed: ${successCount}/${results.length} actions successful`);
|
|
288
|
+
return results;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Execute a single remediation action
|
|
292
|
+
*/
|
|
293
|
+
async executeRemediationAction(action) {
|
|
294
|
+
const startTime = Date.now();
|
|
295
|
+
try {
|
|
296
|
+
let backupPath;
|
|
297
|
+
// Create backup if enabled
|
|
298
|
+
if (action.backup.enabled && action.target.file) {
|
|
299
|
+
backupPath = await this.createBackup(action.target.file);
|
|
300
|
+
}
|
|
301
|
+
// Execute the action based on type
|
|
302
|
+
switch (action.type) {
|
|
303
|
+
case "replace":
|
|
304
|
+
await this.executeReplaceAction(action);
|
|
305
|
+
break;
|
|
306
|
+
case "insert":
|
|
307
|
+
await this.executeInsertAction(action);
|
|
308
|
+
break;
|
|
309
|
+
case "delete":
|
|
310
|
+
await this.executeDeleteAction(action);
|
|
311
|
+
break;
|
|
312
|
+
case "config":
|
|
313
|
+
await this.executeConfigAction(action);
|
|
314
|
+
break;
|
|
315
|
+
case "file":
|
|
316
|
+
await this.executeFileAction(action);
|
|
317
|
+
break;
|
|
318
|
+
default:
|
|
319
|
+
throw new Error(`Unknown action type: ${action.type}`);
|
|
320
|
+
}
|
|
321
|
+
// Validate the fix if validation is provided
|
|
322
|
+
let validationResult;
|
|
323
|
+
if (action.validation && action.target.file) {
|
|
324
|
+
validationResult = await this.validateRemediation(action);
|
|
325
|
+
}
|
|
326
|
+
return {
|
|
327
|
+
vulnerabilityId: action.id,
|
|
328
|
+
success: true,
|
|
329
|
+
action: action.type,
|
|
330
|
+
details: `Remediation completed successfully in ${Date.now() - startTime}ms`,
|
|
331
|
+
timestamp: new Date(),
|
|
332
|
+
backupPath,
|
|
333
|
+
validationResult,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
catch (error) {
|
|
337
|
+
return {
|
|
338
|
+
vulnerabilityId: action.id,
|
|
339
|
+
success: false,
|
|
340
|
+
action: action.type,
|
|
341
|
+
details: `Remediation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
342
|
+
timestamp: new Date(),
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Execute replace action
|
|
348
|
+
*/
|
|
349
|
+
async executeReplaceAction(action) {
|
|
350
|
+
if (!action.target.file || !action.target.pattern || !action.replacement.content) {
|
|
351
|
+
throw new Error("Replace action missing required fields");
|
|
352
|
+
}
|
|
353
|
+
const content = await fs.readFile(action.target.file, "utf-8");
|
|
354
|
+
const updatedContent = content.replace(action.target.pattern, action.replacement.content);
|
|
355
|
+
if (content === updatedContent) {
|
|
356
|
+
throw new Error("No changes made - pattern not found");
|
|
357
|
+
}
|
|
358
|
+
await fs.writeFile(action.target.file, updatedContent, "utf-8");
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Execute insert action
|
|
362
|
+
*/
|
|
363
|
+
async executeInsertAction(action) {
|
|
364
|
+
if (!action.target.file || !action.replacement.content) {
|
|
365
|
+
throw new Error("Insert action missing required fields");
|
|
366
|
+
}
|
|
367
|
+
const content = await fs.readFile(action.target.file, "utf-8");
|
|
368
|
+
const lines = content.split("\n");
|
|
369
|
+
const insertIndex = action.target.line ? Math.max(0, action.target.line - 1) : lines.length;
|
|
370
|
+
lines.splice(insertIndex, 0, action.replacement.content);
|
|
371
|
+
await fs.writeFile(action.target.file, lines.join("\n"), "utf-8");
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Execute delete action
|
|
375
|
+
*/
|
|
376
|
+
async executeDeleteAction(action) {
|
|
377
|
+
if (!action.target.file) {
|
|
378
|
+
throw new Error("Delete action missing file");
|
|
379
|
+
}
|
|
380
|
+
if (action.target.line) {
|
|
381
|
+
// Delete specific line
|
|
382
|
+
const content = await fs.readFile(action.target.file, "utf-8");
|
|
383
|
+
const lines = content.split("\n");
|
|
384
|
+
if (action.target.line > 0 && action.target.line <= lines.length) {
|
|
385
|
+
lines.splice(action.target.line - 1, 1);
|
|
386
|
+
await fs.writeFile(action.target.file, lines.join("\n"), "utf-8");
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
else if (action.target.pattern) {
|
|
390
|
+
// Delete pattern matches
|
|
391
|
+
const content = await fs.readFile(action.target.file, "utf-8");
|
|
392
|
+
const updatedContent = content.replace(action.target.pattern, "");
|
|
393
|
+
await fs.writeFile(action.target.file, updatedContent, "utf-8");
|
|
394
|
+
}
|
|
395
|
+
else {
|
|
396
|
+
throw new Error("Delete action missing target specification");
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Execute config action
|
|
401
|
+
*/
|
|
402
|
+
async executeConfigAction(action) {
|
|
403
|
+
if (!action.target.file || !action.replacement.config) {
|
|
404
|
+
throw new Error("Config action missing required fields");
|
|
405
|
+
}
|
|
406
|
+
const content = await fs.readFile(action.target.file, "utf-8");
|
|
407
|
+
const config = JSON.parse(content);
|
|
408
|
+
// Merge configuration changes
|
|
409
|
+
Object.assign(config, action.replacement.config);
|
|
410
|
+
await fs.writeFile(action.target.file, JSON.stringify(config, null, 2), "utf-8");
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Execute file action
|
|
414
|
+
*/
|
|
415
|
+
async executeFileAction(action) {
|
|
416
|
+
if (!action.replacement.action) {
|
|
417
|
+
throw new Error("File action missing action specification");
|
|
418
|
+
}
|
|
419
|
+
switch (action.replacement.action) {
|
|
420
|
+
case "delete":
|
|
421
|
+
if (action.target.file) {
|
|
422
|
+
await fs.unlink(action.target.file);
|
|
423
|
+
}
|
|
424
|
+
break;
|
|
425
|
+
case "create":
|
|
426
|
+
if (action.target.file && action.replacement.content) {
|
|
427
|
+
await fs.writeFile(action.target.file, action.replacement.content, "utf-8");
|
|
428
|
+
}
|
|
429
|
+
break;
|
|
430
|
+
default:
|
|
431
|
+
throw new Error(`Unknown file action: ${action.replacement.action}`);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Create backup of file
|
|
436
|
+
*/
|
|
437
|
+
async createBackup(filePath) {
|
|
438
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
439
|
+
const backupPath = path.join(this.backupDirectory, `${path.basename(filePath)}.${timestamp}.backup`);
|
|
440
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
441
|
+
await fs.writeFile(backupPath, content, "utf-8");
|
|
442
|
+
console.log(`[Remediation] Created backup: ${backupPath}`);
|
|
443
|
+
return backupPath;
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Ensure backup directory exists
|
|
447
|
+
*/
|
|
448
|
+
async ensureBackupDirectory() {
|
|
449
|
+
try {
|
|
450
|
+
await fs.access(this.backupDirectory);
|
|
451
|
+
}
|
|
452
|
+
catch {
|
|
453
|
+
await fs.mkdir(this.backupDirectory, { recursive: true });
|
|
454
|
+
console.log(`[Remediation] Created backup directory: ${this.backupDirectory}`);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Validate remediation
|
|
459
|
+
*/
|
|
460
|
+
async validateRemediation(action) {
|
|
461
|
+
if (!action.validation?.test || !action.target.file) {
|
|
462
|
+
return true; // No validation specified
|
|
463
|
+
}
|
|
464
|
+
try {
|
|
465
|
+
// This is a simplified validation - in practice you'd run the test command
|
|
466
|
+
const content = await fs.readFile(action.target.file, "utf-8");
|
|
467
|
+
// Simple pattern-based validation
|
|
468
|
+
if (action.target.pattern) {
|
|
469
|
+
const matches = content.match(action.target.pattern);
|
|
470
|
+
return (matches?.length || 0) === (action.validation.expected || 0);
|
|
471
|
+
}
|
|
472
|
+
return true;
|
|
473
|
+
}
|
|
474
|
+
catch (error) {
|
|
475
|
+
console.warn(`[Remediation] Validation failed for action ${action.id}:`, error);
|
|
476
|
+
return false;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Simulate remediation actions for dry run
|
|
481
|
+
*/
|
|
482
|
+
async simulateRemediationActions(actions) {
|
|
483
|
+
const results = [];
|
|
484
|
+
for (const action of actions) {
|
|
485
|
+
results.push({
|
|
486
|
+
vulnerabilityId: action.id,
|
|
487
|
+
success: true,
|
|
488
|
+
action: `${action.type} (simulated)`,
|
|
489
|
+
details: `Would ${action.type} in ${action.target.file || "configuration"}`,
|
|
490
|
+
timestamp: new Date(),
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
return results;
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Get remediation history
|
|
497
|
+
*/
|
|
498
|
+
getRemediationHistory() {
|
|
499
|
+
return [...this.remediationHistory];
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Rollback remediation using backup
|
|
503
|
+
*/
|
|
504
|
+
async rollbackRemediation(backupPath, targetFile) {
|
|
505
|
+
try {
|
|
506
|
+
const backupContent = await fs.readFile(backupPath, "utf-8");
|
|
507
|
+
await fs.writeFile(targetFile, backupContent, "utf-8");
|
|
508
|
+
console.log(`[Remediation] Rolled back ${targetFile} from ${backupPath}`);
|
|
509
|
+
}
|
|
510
|
+
catch (error) {
|
|
511
|
+
throw new SecurityValidationError(`Rollback failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Clean up old backups
|
|
516
|
+
*/
|
|
517
|
+
async cleanupBackups(maxAge = 7 * 24 * 60 * 60 * 1000) {
|
|
518
|
+
try {
|
|
519
|
+
const files = await fs.readdir(this.backupDirectory);
|
|
520
|
+
const now = Date.now();
|
|
521
|
+
for (const file of files) {
|
|
522
|
+
const filePath = path.join(this.backupDirectory, file);
|
|
523
|
+
const stats = await fs.stat(filePath);
|
|
524
|
+
if (now - stats.mtime.getTime() > maxAge) {
|
|
525
|
+
await fs.unlink(filePath);
|
|
526
|
+
console.log(`[Remediation] Cleaned up old backup: ${file}`);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
catch (error) {
|
|
531
|
+
console.warn("[Remediation] Backup cleanup failed:", error);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
//# sourceMappingURL=AutomatedRemediation.js.map
|