mcp-wordpress 2.2.0 → 2.4.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/README.md +503 -0
- package/dist/client/api.d.ts +90 -0
- package/dist/client/api.d.ts.map +1 -1
- package/dist/client/api.js +90 -0
- package/dist/client/api.js.map +1 -1
- 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/dist/tools/media.d.ts +43 -4
- package/dist/tools/media.d.ts.map +1 -1
- package/dist/tools/media.js +43 -4
- package/dist/tools/media.js.map +1 -1
- package/dist/tools/posts.d.ts +225 -4
- package/dist/tools/posts.d.ts.map +1 -1
- package/dist/tools/posts.js +225 -4
- package/dist/tools/posts.js.map +1 -1
- package/docs/DOCKER_PUBLISHING_TROUBLESHOOTING.md +233 -0
- package/docs/PUBLISHING-TROUBLESHOOTING.md +227 -0
- package/docs/api/README.md +53 -11
- package/docs/api/openapi.json +10 -10
- package/docs/api/summary.json +1 -1
- package/docs/api/tools/wp_create_post.md +9 -3
- package/docs/api/tools/wp_delete_post.md +2 -3
- package/docs/api/tools/wp_get_current_user.md +7 -1
- package/docs/api/tools/wp_get_post.md +2 -3
- package/docs/api/tools/wp_get_post_revisions.md +1 -1
- package/docs/api/tools/wp_list_posts.md +10 -3
- package/docs/api/tools/wp_list_users.md +8 -1
- package/docs/api/tools/wp_search_site.md +8 -1
- package/docs/api/tools/wp_test_auth.md +8 -1
- package/docs/api/tools/wp_update_post.md +2 -3
- package/docs/examples/docker-production.md +801 -0
- package/docs/examples/multi-site-setup.md +575 -0
- package/docs/examples/single-site-setup.md +390 -0
- package/docs/examples/use-case-workflows.md +469 -0
- package/package.json +11 -3
- package/src/client/api.ts +90 -0
- 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
- package/src/tools/media.ts +43 -4
- package/src/tools/posts.ts +225 -4
|
@@ -0,0 +1,683 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI-Powered Security Code Reviewer
|
|
3
|
+
* Provides intelligent security code review and analysis
|
|
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
|
+
* Comprehensive security review rules
|
|
11
|
+
*/
|
|
12
|
+
const SECURITY_REVIEW_RULES = [
|
|
13
|
+
// Authentication Rules
|
|
14
|
+
{
|
|
15
|
+
id: "auth-001",
|
|
16
|
+
name: "Hardcoded Credentials",
|
|
17
|
+
description: "Detects hardcoded passwords, API keys, and secrets",
|
|
18
|
+
category: "authentication",
|
|
19
|
+
severity: "critical",
|
|
20
|
+
pattern: /(password|secret|key|token)\s*[:=]\s*['"][^'"]{8,}['"]/gi,
|
|
21
|
+
message: "Hardcoded credential detected",
|
|
22
|
+
recommendation: "Use environment variables or secure credential storage",
|
|
23
|
+
cweId: "CWE-798",
|
|
24
|
+
examples: {
|
|
25
|
+
vulnerable: `const password = "mysecretpassword123";`,
|
|
26
|
+
secure: `const password = process.env.DB_PASSWORD;`,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: "auth-002",
|
|
31
|
+
name: "Weak Password Policy",
|
|
32
|
+
description: "Detects weak password validation",
|
|
33
|
+
category: "authentication",
|
|
34
|
+
severity: "medium",
|
|
35
|
+
pattern: /password.*length.*[<>]\s*[1-7]\b/gi,
|
|
36
|
+
message: "Weak password length requirement",
|
|
37
|
+
recommendation: "Enforce minimum 8-character passwords with complexity requirements",
|
|
38
|
+
cweId: "CWE-521",
|
|
39
|
+
examples: {
|
|
40
|
+
vulnerable: `if (password.length < 6) return false;`,
|
|
41
|
+
secure: `if (password.length < 8 || !/(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)/.test(password)) return false;`,
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: "auth-003",
|
|
46
|
+
name: "JWT Secret Exposure",
|
|
47
|
+
description: "Detects exposed JWT secrets",
|
|
48
|
+
category: "authentication",
|
|
49
|
+
severity: "critical",
|
|
50
|
+
pattern: /jwt.*secret.*[:=].*['"][^'"]+['"]/gi,
|
|
51
|
+
message: "JWT secret should not be hardcoded",
|
|
52
|
+
recommendation: "Store JWT secret in environment variables",
|
|
53
|
+
cweId: "CWE-798",
|
|
54
|
+
examples: {
|
|
55
|
+
vulnerable: `const jwtSecret = "my-jwt-secret-key";`,
|
|
56
|
+
secure: `const jwtSecret = process.env.JWT_SECRET;`,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
// Input Validation Rules
|
|
60
|
+
{
|
|
61
|
+
id: "input-001",
|
|
62
|
+
name: "SQL Injection Risk",
|
|
63
|
+
description: "Detects potential SQL injection vulnerabilities",
|
|
64
|
+
category: "input-validation",
|
|
65
|
+
severity: "critical",
|
|
66
|
+
pattern: /(SELECT|INSERT|UPDATE|DELETE).*?[\+].*?(WHERE|FROM|INTO)/gi,
|
|
67
|
+
message: "Potential SQL injection vulnerability",
|
|
68
|
+
recommendation: "Use parameterized queries or prepared statements",
|
|
69
|
+
cweId: "CWE-89",
|
|
70
|
+
examples: {
|
|
71
|
+
vulnerable: `query = "SELECT * FROM users WHERE id = " + userId;`,
|
|
72
|
+
secure: `query = "SELECT * FROM users WHERE id = ?"; db.query(query, [userId]);`,
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
id: "input-002",
|
|
77
|
+
name: "XSS Vulnerability",
|
|
78
|
+
description: "Detects potential XSS vulnerabilities",
|
|
79
|
+
category: "input-validation",
|
|
80
|
+
severity: "high",
|
|
81
|
+
pattern: /innerHTML\s*=\s*[^;]+userInput/gi,
|
|
82
|
+
message: "Potential XSS vulnerability through innerHTML",
|
|
83
|
+
recommendation: "Use textContent or sanitize input before setting innerHTML",
|
|
84
|
+
cweId: "CWE-79",
|
|
85
|
+
examples: {
|
|
86
|
+
vulnerable: `element.innerHTML = userInput;`,
|
|
87
|
+
secure: `element.textContent = userInput; // or sanitize userInput`,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: "input-003",
|
|
92
|
+
name: "Command Injection",
|
|
93
|
+
description: "Detects potential command injection vulnerabilities",
|
|
94
|
+
category: "input-validation",
|
|
95
|
+
severity: "critical",
|
|
96
|
+
pattern: /exec\(.*?[\+].*?\)/gi,
|
|
97
|
+
message: "Potential command injection vulnerability",
|
|
98
|
+
recommendation: "Validate input and use safe APIs",
|
|
99
|
+
cweId: "CWE-78",
|
|
100
|
+
examples: {
|
|
101
|
+
vulnerable: `exec("ls " + userInput);`,
|
|
102
|
+
secure: `execFile("ls", [userInput]);`,
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
// Authorization Rules
|
|
106
|
+
{
|
|
107
|
+
id: "authz-001",
|
|
108
|
+
name: "Missing Authorization Check",
|
|
109
|
+
description: "Detects endpoints without authorization checks",
|
|
110
|
+
category: "authorization",
|
|
111
|
+
severity: "high",
|
|
112
|
+
pattern: /app\.(get|post|put|delete)\(['"][^'"]*['"],\s*(?!.*auth|.*login)[^)]*\)/gi,
|
|
113
|
+
message: "Endpoint may be missing authorization check",
|
|
114
|
+
recommendation: "Add authorization middleware to protected endpoints",
|
|
115
|
+
cweId: "CWE-862",
|
|
116
|
+
examples: {
|
|
117
|
+
vulnerable: `app.get("/admin/users", (req, res) => { ... });`,
|
|
118
|
+
secure: `app.get("/admin/users", authMiddleware, (req, res) => { ... });`,
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
id: "authz-002",
|
|
123
|
+
name: "Privilege Escalation Risk",
|
|
124
|
+
description: "Detects potential privilege escalation",
|
|
125
|
+
category: "authorization",
|
|
126
|
+
severity: "high",
|
|
127
|
+
pattern: /role\s*=\s*['"]admin['"]|isAdmin\s*=\s*true/gi,
|
|
128
|
+
message: "Potential privilege escalation through role assignment",
|
|
129
|
+
recommendation: "Validate user permissions before role assignment",
|
|
130
|
+
cweId: "CWE-269",
|
|
131
|
+
examples: {
|
|
132
|
+
vulnerable: `user.role = "admin";`,
|
|
133
|
+
secure: `if (currentUser.canAssignRole("admin")) user.role = "admin";`,
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
// Cryptography Rules
|
|
137
|
+
{
|
|
138
|
+
id: "crypto-001",
|
|
139
|
+
name: "Weak Encryption Algorithm",
|
|
140
|
+
description: "Detects use of weak encryption algorithms",
|
|
141
|
+
category: "crypto",
|
|
142
|
+
severity: "high",
|
|
143
|
+
pattern: /(md5|sha1|des|rc4|3des)/gi,
|
|
144
|
+
message: "Weak cryptographic algorithm detected",
|
|
145
|
+
recommendation: "Use strong algorithms like AES-256, SHA-256, or bcrypt",
|
|
146
|
+
cweId: "CWE-327",
|
|
147
|
+
examples: {
|
|
148
|
+
vulnerable: `const hash = crypto.createHash("md5");`,
|
|
149
|
+
secure: `const hash = crypto.createHash("sha256");`,
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
id: "crypto-002",
|
|
154
|
+
name: "Hardcoded Encryption Key",
|
|
155
|
+
description: "Detects hardcoded encryption keys",
|
|
156
|
+
category: "crypto",
|
|
157
|
+
severity: "critical",
|
|
158
|
+
pattern: /encrypt.*key.*[:=].*['"][^'"]{16,}['"]/gi,
|
|
159
|
+
message: "Hardcoded encryption key detected",
|
|
160
|
+
recommendation: "Generate keys securely and store in environment variables",
|
|
161
|
+
cweId: "CWE-798",
|
|
162
|
+
examples: {
|
|
163
|
+
vulnerable: `const encryptionKey = "1234567890abcdef";`,
|
|
164
|
+
secure: `const encryptionKey = process.env.ENCRYPTION_KEY;`,
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
// Session Management Rules
|
|
168
|
+
{
|
|
169
|
+
id: "session-001",
|
|
170
|
+
name: "Insecure Session Configuration",
|
|
171
|
+
description: "Detects insecure session settings",
|
|
172
|
+
category: "session",
|
|
173
|
+
severity: "medium",
|
|
174
|
+
pattern: /session.*secure\s*:\s*false|httpOnly\s*:\s*false/gi,
|
|
175
|
+
message: "Insecure session configuration",
|
|
176
|
+
recommendation: "Enable secure and httpOnly flags for sessions",
|
|
177
|
+
cweId: "CWE-614",
|
|
178
|
+
examples: {
|
|
179
|
+
vulnerable: `session({ secure: false, httpOnly: false })`,
|
|
180
|
+
secure: `session({ secure: true, httpOnly: true })`,
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
id: "session-002",
|
|
185
|
+
name: "Session Fixation Risk",
|
|
186
|
+
description: "Detects potential session fixation vulnerabilities",
|
|
187
|
+
category: "session",
|
|
188
|
+
severity: "medium",
|
|
189
|
+
pattern: /login.*(?!regenerate)/gi,
|
|
190
|
+
message: "Login may not regenerate session ID",
|
|
191
|
+
recommendation: "Regenerate session ID after successful login",
|
|
192
|
+
cweId: "CWE-384",
|
|
193
|
+
examples: {
|
|
194
|
+
vulnerable: `// Login without session regeneration`,
|
|
195
|
+
secure: `req.session.regenerate(() => { /* login success */ });`,
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
// Configuration Rules
|
|
199
|
+
{
|
|
200
|
+
id: "config-001",
|
|
201
|
+
name: "Debug Mode in Production",
|
|
202
|
+
description: "Detects debug mode enabled",
|
|
203
|
+
category: "config",
|
|
204
|
+
severity: "medium",
|
|
205
|
+
pattern: /debug\s*[:=]\s*true|DEBUG\s*=\s*['"]?true['"]?/gi,
|
|
206
|
+
message: "Debug mode may be enabled in production",
|
|
207
|
+
recommendation: "Disable debug mode in production environments",
|
|
208
|
+
cweId: "CWE-489",
|
|
209
|
+
examples: {
|
|
210
|
+
vulnerable: `const debug = true;`,
|
|
211
|
+
secure: `const debug = process.env.NODE_ENV !== 'production';`,
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
id: "config-002",
|
|
216
|
+
name: "HTTPS Disabled",
|
|
217
|
+
description: "Detects HTTP instead of HTTPS",
|
|
218
|
+
category: "config",
|
|
219
|
+
severity: "medium",
|
|
220
|
+
pattern: /http:\/\/(?!localhost|127\.0\.0\.1)/gi,
|
|
221
|
+
message: "HTTP URL detected in production code",
|
|
222
|
+
recommendation: "Use HTTPS for all external communications",
|
|
223
|
+
cweId: "CWE-319",
|
|
224
|
+
examples: {
|
|
225
|
+
vulnerable: `const apiUrl = "http://api.example.com";`,
|
|
226
|
+
secure: `const apiUrl = "https://api.example.com";`,
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
// General Security Rules
|
|
230
|
+
{
|
|
231
|
+
id: "general-001",
|
|
232
|
+
name: "Error Information Disclosure",
|
|
233
|
+
description: "Detects potential information disclosure through errors",
|
|
234
|
+
category: "general",
|
|
235
|
+
severity: "low",
|
|
236
|
+
pattern: /throw.*error.*stack|console\.error.*stack/gi,
|
|
237
|
+
message: "Error may disclose sensitive information",
|
|
238
|
+
recommendation: "Log detailed errors securely, return generic errors to users",
|
|
239
|
+
cweId: "CWE-209",
|
|
240
|
+
examples: {
|
|
241
|
+
vulnerable: `throw new Error(err.stack);`,
|
|
242
|
+
secure: `logger.error(err.stack); throw new Error("An error occurred");`,
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
id: "general-002",
|
|
247
|
+
name: "Unsafe Random Generation",
|
|
248
|
+
description: "Detects use of unsafe random number generation",
|
|
249
|
+
category: "general",
|
|
250
|
+
severity: "medium",
|
|
251
|
+
pattern: /Math\.random\(\)/gi,
|
|
252
|
+
message: "Math.random() is not cryptographically secure",
|
|
253
|
+
recommendation: "Use crypto.randomBytes() for security-sensitive random generation",
|
|
254
|
+
cweId: "CWE-338",
|
|
255
|
+
examples: {
|
|
256
|
+
vulnerable: `const token = Math.random().toString(36);`,
|
|
257
|
+
secure: `const token = crypto.randomBytes(32).toString('hex');`,
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
];
|
|
261
|
+
/**
|
|
262
|
+
* AI-Powered Security Code Reviewer
|
|
263
|
+
*/
|
|
264
|
+
export class SecurityReviewer {
|
|
265
|
+
reviewHistory = [];
|
|
266
|
+
/**
|
|
267
|
+
* Perform comprehensive security review of a file
|
|
268
|
+
*/
|
|
269
|
+
async reviewFile(filePath, options = {}) {
|
|
270
|
+
const reviewId = SecurityUtils.generateSecureToken(16);
|
|
271
|
+
console.log(`[Security Reviewer] Reviewing file: ${filePath}`);
|
|
272
|
+
try {
|
|
273
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
274
|
+
const lines = content.split("\n");
|
|
275
|
+
// Apply security rules
|
|
276
|
+
const findings = await this.applySecurityRules(content, lines, options);
|
|
277
|
+
// Perform AI analysis if requested
|
|
278
|
+
let aiAnalysis;
|
|
279
|
+
if (options.aiAnalysis) {
|
|
280
|
+
aiAnalysis = await this.performAIAnalysis(content, findings);
|
|
281
|
+
}
|
|
282
|
+
// Generate summary
|
|
283
|
+
const summary = this.generateSummary(findings);
|
|
284
|
+
const overallRating = this.calculateOverallRating(summary);
|
|
285
|
+
const recommendations = this.generateRecommendations(findings, aiAnalysis);
|
|
286
|
+
const result = {
|
|
287
|
+
reviewId,
|
|
288
|
+
timestamp: new Date(),
|
|
289
|
+
file: filePath,
|
|
290
|
+
findings,
|
|
291
|
+
summary,
|
|
292
|
+
overallRating,
|
|
293
|
+
recommendations,
|
|
294
|
+
};
|
|
295
|
+
this.reviewHistory.push(result);
|
|
296
|
+
console.log(`[Security Reviewer] Review completed: ${findings.length} findings`);
|
|
297
|
+
return result;
|
|
298
|
+
}
|
|
299
|
+
catch (error) {
|
|
300
|
+
console.error(`[Security Reviewer] Review failed for ${filePath}:`, error);
|
|
301
|
+
throw new SecurityValidationError("Security review failed", [{ message: String(error) }]);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Review multiple files
|
|
306
|
+
*/
|
|
307
|
+
async reviewDirectory(dirPath, options = {}) {
|
|
308
|
+
console.log(`[Security Reviewer] Reviewing directory: ${dirPath}`);
|
|
309
|
+
const results = [];
|
|
310
|
+
const filePattern = options.filePattern || /\.(ts|js|jsx|tsx)$/;
|
|
311
|
+
try {
|
|
312
|
+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
313
|
+
for (const entry of entries) {
|
|
314
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
315
|
+
if (entry.isDirectory() && options.recursive && !entry.name.startsWith(".")) {
|
|
316
|
+
const subResults = await this.reviewDirectory(fullPath, options);
|
|
317
|
+
results.push(...subResults);
|
|
318
|
+
}
|
|
319
|
+
else if (entry.isFile() && filePattern.test(entry.name)) {
|
|
320
|
+
const result = await this.reviewFile(fullPath, options);
|
|
321
|
+
results.push(result);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return results;
|
|
325
|
+
}
|
|
326
|
+
catch (error) {
|
|
327
|
+
console.error(`[Security Reviewer] Directory review failed for ${dirPath}:`, error);
|
|
328
|
+
throw new SecurityValidationError("Directory review failed", [{ message: String(error) }]);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Apply security rules to code content
|
|
333
|
+
*/
|
|
334
|
+
async applySecurityRules(content, lines, options) {
|
|
335
|
+
const findings = [];
|
|
336
|
+
const applicableRules = this.getApplicableRules(options);
|
|
337
|
+
for (const rule of applicableRules) {
|
|
338
|
+
const matches = Array.from(content.matchAll(rule.pattern));
|
|
339
|
+
for (const match of matches) {
|
|
340
|
+
if (match.index !== undefined) {
|
|
341
|
+
const lineNumber = this.getLineNumber(content, match.index);
|
|
342
|
+
const columnNumber = this.getColumnNumber(content, match.index);
|
|
343
|
+
findings.push({
|
|
344
|
+
id: `${rule.id}-${Date.now()}-${findings.length}`,
|
|
345
|
+
rule: rule.id,
|
|
346
|
+
severity: rule.severity,
|
|
347
|
+
line: lineNumber,
|
|
348
|
+
column: columnNumber,
|
|
349
|
+
code: lines[lineNumber - 1]?.trim() || "",
|
|
350
|
+
message: rule.message,
|
|
351
|
+
recommendation: rule.recommendation,
|
|
352
|
+
confidence: this.calculateConfidence(rule, match[0]),
|
|
353
|
+
category: rule.category,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return findings;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Get applicable security rules based on options
|
|
362
|
+
*/
|
|
363
|
+
getApplicableRules(options) {
|
|
364
|
+
let rules = SECURITY_REVIEW_RULES;
|
|
365
|
+
if (options.rules) {
|
|
366
|
+
rules = rules.filter((rule) => options.rules.includes(rule.id));
|
|
367
|
+
}
|
|
368
|
+
if (options.excludeRules) {
|
|
369
|
+
rules = rules.filter((rule) => !options.excludeRules.includes(rule.id));
|
|
370
|
+
}
|
|
371
|
+
return rules;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Perform AI-powered code analysis
|
|
375
|
+
*/
|
|
376
|
+
async performAIAnalysis(content, findings) {
|
|
377
|
+
// Simplified AI analysis - in practice this would use machine learning
|
|
378
|
+
const complexity = this.calculateComplexity(content);
|
|
379
|
+
const securityScore = this.calculateSecurityScore(findings, content.length);
|
|
380
|
+
const patterns = this.analyzePatterns(content);
|
|
381
|
+
const recommendations = this.generateAIRecommendations(findings, patterns);
|
|
382
|
+
const riskAssessment = this.assessRisk(findings, complexity);
|
|
383
|
+
return {
|
|
384
|
+
complexity,
|
|
385
|
+
securityScore,
|
|
386
|
+
patterns,
|
|
387
|
+
recommendations,
|
|
388
|
+
riskAssessment,
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Calculate code complexity
|
|
393
|
+
*/
|
|
394
|
+
calculateComplexity(content) {
|
|
395
|
+
const complexityFactors = [
|
|
396
|
+
(content.match(/if\s*\(/g) || []).length * 1,
|
|
397
|
+
(content.match(/for\s*\(/g) || []).length * 2,
|
|
398
|
+
(content.match(/while\s*\(/g) || []).length * 2,
|
|
399
|
+
(content.match(/switch\s*\(/g) || []).length * 3,
|
|
400
|
+
(content.match(/try\s*\{/g) || []).length * 2,
|
|
401
|
+
(content.match(/catch\s*\(/g) || []).length * 2,
|
|
402
|
+
];
|
|
403
|
+
return complexityFactors.reduce((sum, factor) => sum + factor, 0);
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Calculate security score
|
|
407
|
+
*/
|
|
408
|
+
calculateSecurityScore(findings, codeLength) {
|
|
409
|
+
const severityWeights = { critical: 10, high: 7, medium: 4, low: 2, info: 1 };
|
|
410
|
+
const penalty = findings.reduce((sum, finding) => {
|
|
411
|
+
return sum + severityWeights[finding.severity];
|
|
412
|
+
}, 0);
|
|
413
|
+
const normalizedPenalty = penalty / (codeLength / 1000); // Normalize by code size
|
|
414
|
+
return Math.max(0, 100 - normalizedPenalty);
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Analyze code patterns
|
|
418
|
+
*/
|
|
419
|
+
analyzePatterns(content) {
|
|
420
|
+
const positive = [];
|
|
421
|
+
const negative = [];
|
|
422
|
+
// Positive patterns
|
|
423
|
+
if (/process\.env\./g.test(content))
|
|
424
|
+
positive.push("Uses environment variables");
|
|
425
|
+
if (/try\s*\{[\s\S]*catch/g.test(content))
|
|
426
|
+
positive.push("Implements error handling");
|
|
427
|
+
if (/crypto\.randomBytes/g.test(content))
|
|
428
|
+
positive.push("Uses secure random generation");
|
|
429
|
+
if (/bcrypt/g.test(content))
|
|
430
|
+
positive.push("Uses secure password hashing");
|
|
431
|
+
if (/https:\/\//g.test(content))
|
|
432
|
+
positive.push("Uses HTTPS URLs");
|
|
433
|
+
// Negative patterns
|
|
434
|
+
if (/eval\s*\(/g.test(content))
|
|
435
|
+
negative.push("Uses dangerous eval() function");
|
|
436
|
+
if (/innerHTML.*\+/g.test(content))
|
|
437
|
+
negative.push("Potential XSS through innerHTML concatenation");
|
|
438
|
+
if (/password.*=.*['"][^'"]{1,7}['"]/g.test(content))
|
|
439
|
+
negative.push("Weak passwords detected");
|
|
440
|
+
if (/http:\/\/(?!localhost)/g.test(content))
|
|
441
|
+
negative.push("Uses insecure HTTP URLs");
|
|
442
|
+
return { positive, negative };
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Generate AI recommendations
|
|
446
|
+
*/
|
|
447
|
+
generateAIRecommendations(findings, patterns) {
|
|
448
|
+
const recommendations = [];
|
|
449
|
+
// High-level recommendations based on findings
|
|
450
|
+
const criticalFindings = findings.filter((f) => f.severity === "critical");
|
|
451
|
+
if (criticalFindings.length > 0) {
|
|
452
|
+
recommendations.push("Address critical security vulnerabilities immediately");
|
|
453
|
+
}
|
|
454
|
+
const authFindings = findings.filter((f) => f.category === "authentication");
|
|
455
|
+
if (authFindings.length > 2) {
|
|
456
|
+
recommendations.push("Review and strengthen authentication mechanisms");
|
|
457
|
+
}
|
|
458
|
+
const inputFindings = findings.filter((f) => f.category === "input-validation");
|
|
459
|
+
if (inputFindings.length > 0) {
|
|
460
|
+
recommendations.push("Implement comprehensive input validation and sanitization");
|
|
461
|
+
}
|
|
462
|
+
// Recommendations based on patterns
|
|
463
|
+
if (patterns.negative.length > patterns.positive.length) {
|
|
464
|
+
recommendations.push("Consider refactoring to follow security best practices");
|
|
465
|
+
}
|
|
466
|
+
if (patterns.negative.includes("Uses dangerous eval() function")) {
|
|
467
|
+
recommendations.push("Replace eval() with safer alternatives like JSON.parse()");
|
|
468
|
+
}
|
|
469
|
+
return recommendations;
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Assess overall risk
|
|
473
|
+
*/
|
|
474
|
+
assessRisk(findings, complexity) {
|
|
475
|
+
const factors = [];
|
|
476
|
+
let riskScore = 0;
|
|
477
|
+
// Risk based on findings
|
|
478
|
+
const criticalCount = findings.filter((f) => f.severity === "critical").length;
|
|
479
|
+
const highCount = findings.filter((f) => f.severity === "high").length;
|
|
480
|
+
riskScore += criticalCount * 10 + highCount * 5;
|
|
481
|
+
if (criticalCount > 0)
|
|
482
|
+
factors.push(`${criticalCount} critical vulnerabilities`);
|
|
483
|
+
if (highCount > 0)
|
|
484
|
+
factors.push(`${highCount} high-severity vulnerabilities`);
|
|
485
|
+
// Risk based on complexity
|
|
486
|
+
if (complexity > 50) {
|
|
487
|
+
riskScore += 10;
|
|
488
|
+
factors.push("High code complexity");
|
|
489
|
+
}
|
|
490
|
+
// Risk based on categories
|
|
491
|
+
const authVulns = findings.filter((f) => f.category === "authentication").length;
|
|
492
|
+
if (authVulns > 0) {
|
|
493
|
+
riskScore += authVulns * 3;
|
|
494
|
+
factors.push("Authentication vulnerabilities");
|
|
495
|
+
}
|
|
496
|
+
// Determine risk level
|
|
497
|
+
let level;
|
|
498
|
+
if (riskScore >= 30)
|
|
499
|
+
level = "critical";
|
|
500
|
+
else if (riskScore >= 20)
|
|
501
|
+
level = "high";
|
|
502
|
+
else if (riskScore >= 10)
|
|
503
|
+
level = "medium";
|
|
504
|
+
else
|
|
505
|
+
level = "low";
|
|
506
|
+
return { level, factors };
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Calculate confidence score for a finding
|
|
510
|
+
*/
|
|
511
|
+
calculateConfidence(rule, match) {
|
|
512
|
+
// Base confidence varies by rule type
|
|
513
|
+
let confidence = 0.7;
|
|
514
|
+
// Adjust based on match characteristics
|
|
515
|
+
if (match.length > 50)
|
|
516
|
+
confidence += 0.1; // Longer matches are more likely to be intentional
|
|
517
|
+
if (/\w{20,}/.test(match))
|
|
518
|
+
confidence += 0.1; // Long strings suggest real credentials
|
|
519
|
+
if (rule.category === "authentication")
|
|
520
|
+
confidence += 0.1; // Auth issues are commonly overlooked
|
|
521
|
+
return Math.min(1.0, confidence);
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Generate summary of findings
|
|
525
|
+
*/
|
|
526
|
+
generateSummary(findings) {
|
|
527
|
+
return {
|
|
528
|
+
totalFindings: findings.length,
|
|
529
|
+
criticalFindings: findings.filter((f) => f.severity === "critical").length,
|
|
530
|
+
highFindings: findings.filter((f) => f.severity === "high").length,
|
|
531
|
+
mediumFindings: findings.filter((f) => f.severity === "medium").length,
|
|
532
|
+
lowFindings: findings.filter((f) => f.severity === "low").length,
|
|
533
|
+
infoFindings: findings.filter((f) => f.severity === "info").length,
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Calculate overall security rating
|
|
538
|
+
*/
|
|
539
|
+
calculateOverallRating(summary) {
|
|
540
|
+
if (summary.criticalFindings > 0)
|
|
541
|
+
return "critical";
|
|
542
|
+
if (summary.highFindings > 2)
|
|
543
|
+
return "vulnerable";
|
|
544
|
+
if (summary.highFindings > 0 || summary.mediumFindings > 3)
|
|
545
|
+
return "needs-review";
|
|
546
|
+
return "secure";
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Generate recommendations based on findings
|
|
550
|
+
*/
|
|
551
|
+
generateRecommendations(findings, aiAnalysis) {
|
|
552
|
+
const recommendations = [];
|
|
553
|
+
// Priority recommendations based on severity
|
|
554
|
+
const criticalFindings = findings.filter((f) => f.severity === "critical");
|
|
555
|
+
if (criticalFindings.length > 0) {
|
|
556
|
+
recommendations.push("Immediately address critical security vulnerabilities");
|
|
557
|
+
recommendations.push("Review credential management and move secrets to environment variables");
|
|
558
|
+
}
|
|
559
|
+
// Category-specific recommendations
|
|
560
|
+
const categories = [...new Set(findings.map((f) => f.category))];
|
|
561
|
+
if (categories.includes("authentication")) {
|
|
562
|
+
recommendations.push("Strengthen authentication mechanisms and credential handling");
|
|
563
|
+
}
|
|
564
|
+
if (categories.includes("input-validation")) {
|
|
565
|
+
recommendations.push("Implement comprehensive input validation and output encoding");
|
|
566
|
+
}
|
|
567
|
+
if (categories.includes("crypto")) {
|
|
568
|
+
recommendations.push("Update to use strong cryptographic algorithms and secure key management");
|
|
569
|
+
}
|
|
570
|
+
// Add AI recommendations if available
|
|
571
|
+
if (aiAnalysis) {
|
|
572
|
+
recommendations.push(...aiAnalysis.recommendations);
|
|
573
|
+
}
|
|
574
|
+
return [...new Set(recommendations)]; // Remove duplicates
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Get line number from character index
|
|
578
|
+
*/
|
|
579
|
+
getLineNumber(content, index) {
|
|
580
|
+
return content.substring(0, index).split("\n").length;
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Get column number from character index
|
|
584
|
+
*/
|
|
585
|
+
getColumnNumber(content, index) {
|
|
586
|
+
const lines = content.substring(0, index).split("\n");
|
|
587
|
+
return lines[lines.length - 1].length + 1;
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* Get review history
|
|
591
|
+
*/
|
|
592
|
+
getReviewHistory() {
|
|
593
|
+
return [...this.reviewHistory];
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Get security rules
|
|
597
|
+
*/
|
|
598
|
+
getSecurityRules() {
|
|
599
|
+
return [...SECURITY_REVIEW_RULES];
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Add custom security rule
|
|
603
|
+
*/
|
|
604
|
+
addCustomRule(rule) {
|
|
605
|
+
SECURITY_REVIEW_RULES.push(rule);
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Remove security rule
|
|
609
|
+
*/
|
|
610
|
+
removeRule(ruleId) {
|
|
611
|
+
const index = SECURITY_REVIEW_RULES.findIndex((rule) => rule.id === ruleId);
|
|
612
|
+
if (index !== -1) {
|
|
613
|
+
SECURITY_REVIEW_RULES.splice(index, 1);
|
|
614
|
+
return true;
|
|
615
|
+
}
|
|
616
|
+
return false;
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Generate security report
|
|
620
|
+
*/
|
|
621
|
+
generateSecurityReport(results) {
|
|
622
|
+
const summary = {
|
|
623
|
+
filesReviewed: results.length,
|
|
624
|
+
totalFindings: results.reduce((sum, r) => sum + r.findings.length, 0),
|
|
625
|
+
criticalFindings: results.reduce((sum, r) => sum + r.summary.criticalFindings, 0),
|
|
626
|
+
highFindings: results.reduce((sum, r) => sum + r.summary.highFindings, 0),
|
|
627
|
+
overallRating: this.calculateProjectRating(results),
|
|
628
|
+
};
|
|
629
|
+
const allFindings = results.flatMap((r) => r.findings);
|
|
630
|
+
const topIssues = allFindings
|
|
631
|
+
.filter((f) => f.severity === "critical" || f.severity === "high")
|
|
632
|
+
.sort((a, b) => {
|
|
633
|
+
const severityOrder = { critical: 4, high: 3, medium: 2, low: 1, info: 0 };
|
|
634
|
+
return severityOrder[b.severity] - severityOrder[a.severity];
|
|
635
|
+
})
|
|
636
|
+
.slice(0, 10);
|
|
637
|
+
const recommendations = [...new Set(results.flatMap((r) => r.recommendations))];
|
|
638
|
+
const riskFactors = this.identifyRiskFactors(results);
|
|
639
|
+
return {
|
|
640
|
+
summary,
|
|
641
|
+
topIssues,
|
|
642
|
+
recommendations,
|
|
643
|
+
riskFactors,
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Calculate overall project security rating
|
|
648
|
+
*/
|
|
649
|
+
calculateProjectRating(results) {
|
|
650
|
+
const criticalCount = results.reduce((sum, r) => sum + r.summary.criticalFindings, 0);
|
|
651
|
+
const highCount = results.reduce((sum, r) => sum + r.summary.highFindings, 0);
|
|
652
|
+
const criticalFiles = results.filter((r) => r.overallRating === "critical").length;
|
|
653
|
+
if (criticalCount > 0 || criticalFiles > 0)
|
|
654
|
+
return "critical";
|
|
655
|
+
if (highCount > 5 || results.filter((r) => r.overallRating === "vulnerable").length > 2)
|
|
656
|
+
return "vulnerable";
|
|
657
|
+
if (highCount > 0 || results.filter((r) => r.overallRating === "needs-review").length > 0)
|
|
658
|
+
return "needs-review";
|
|
659
|
+
return "secure";
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* Identify project-wide risk factors
|
|
663
|
+
*/
|
|
664
|
+
identifyRiskFactors(results) {
|
|
665
|
+
const factors = [];
|
|
666
|
+
const allFindings = results.flatMap((r) => r.findings);
|
|
667
|
+
const authIssues = allFindings.filter((f) => f.category === "authentication").length;
|
|
668
|
+
if (authIssues > 3)
|
|
669
|
+
factors.push("Multiple authentication vulnerabilities");
|
|
670
|
+
const cryptoIssues = allFindings.filter((f) => f.category === "crypto").length;
|
|
671
|
+
if (cryptoIssues > 0)
|
|
672
|
+
factors.push("Cryptographic implementation issues");
|
|
673
|
+
const inputIssues = allFindings.filter((f) => f.category === "input-validation").length;
|
|
674
|
+
if (inputIssues > 5)
|
|
675
|
+
factors.push("Widespread input validation issues");
|
|
676
|
+
const vulnerableFiles = results.filter((r) => r.overallRating === "vulnerable" || r.overallRating === "critical").length;
|
|
677
|
+
const totalFiles = results.length;
|
|
678
|
+
if (vulnerableFiles / totalFiles > 0.3)
|
|
679
|
+
factors.push("High percentage of vulnerable files");
|
|
680
|
+
return factors;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
//# sourceMappingURL=SecurityReviewer.js.map
|