@indicated/vibeguard 1.4.0 → 1.5.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.
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAoBA,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAqPpD"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAwQA,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CA+OpD"}
@@ -38,6 +38,7 @@ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
38
38
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
39
39
  const zod_1 = require("zod");
40
40
  const path = __importStar(require("path"));
41
+ const fs = __importStar(require("fs"));
41
42
  const scanner_1 = require("../scanner");
42
43
  const definitions_1 = require("../scanner/rules/definitions");
43
44
  const license_1 = require("../api/license");
@@ -58,13 +59,217 @@ function calculateGrade(counts) {
58
59
  return 'A';
59
60
  return 'A+';
60
61
  }
62
+ function getCodeSnippet(filePath, line, contextLines = 3) {
63
+ try {
64
+ const content = fs.readFileSync(filePath, 'utf-8');
65
+ const lines = content.split('\n');
66
+ const startLine = Math.max(0, line - contextLines - 1);
67
+ const endLine = Math.min(lines.length, line + contextLines);
68
+ return lines.slice(startLine, endLine).map((l, i) => {
69
+ const lineNum = startLine + i + 1;
70
+ const marker = lineNum === line ? '→' : ' ';
71
+ return `${marker} ${lineNum.toString().padStart(4)}: ${l}`;
72
+ }).join('\n');
73
+ }
74
+ catch {
75
+ return '(Could not read file)';
76
+ }
77
+ }
78
+ function analyzeContext(finding, cwd) {
79
+ const signals = [];
80
+ let confidence = 'high';
81
+ let question = '';
82
+ const filePath = finding.file;
83
+ const relativePath = path.relative(cwd, filePath).toLowerCase();
84
+ // Read file content for analysis
85
+ let fileContent = '';
86
+ try {
87
+ fileContent = fs.readFileSync(filePath, 'utf-8').toLowerCase();
88
+ }
89
+ catch {
90
+ // Can't read file
91
+ }
92
+ // Analyze based on rule type
93
+ switch (finding.rule.id) {
94
+ case 'xss-innerhtml':
95
+ // Check for sanitizer imports
96
+ if (fileContent.includes('dompurify') || fileContent.includes('sanitize') ||
97
+ fileContent.includes('escapehtml') || fileContent.includes('escape-html')) {
98
+ signals.push({ signal: 'File imports sanitization library', type: 'positive' });
99
+ confidence = 'low';
100
+ }
101
+ // Check if it's static HTML
102
+ if (finding.code.includes("'<") || finding.code.includes('"<') || finding.code.includes('`<')) {
103
+ signals.push({ signal: 'Appears to be static HTML string', type: 'positive' });
104
+ confidence = 'low';
105
+ }
106
+ // Check for user input indicators
107
+ if (finding.code.includes('user') || finding.code.includes('input') ||
108
+ finding.code.includes('req.') || finding.code.includes('params')) {
109
+ signals.push({ signal: 'May contain user-controlled input', type: 'negative' });
110
+ confidence = 'high';
111
+ }
112
+ question = 'Is the data being inserted sanitized before this line? Check if escapeHtml() or similar is called on the variable.';
113
+ break;
114
+ case 'supabase-no-rls':
115
+ // Check if it's server-side
116
+ if (relativePath.includes('/api/') || relativePath.includes('/server/') ||
117
+ relativePath.includes('/routes/') || relativePath.includes('/backend/')) {
118
+ signals.push({ signal: 'File is in server-side directory', type: 'positive' });
119
+ confidence = 'low';
120
+ }
121
+ // Check for service role key
122
+ if (fileContent.includes('service_role') || fileContent.includes('servicerole') ||
123
+ fileContent.includes('supabase_service')) {
124
+ signals.push({ signal: 'Uses service role key (server-side pattern)', type: 'positive' });
125
+ confidence = 'low';
126
+ }
127
+ // Check for auth middleware
128
+ if (fileContent.includes('requireauth') || fileContent.includes('requireadmin') ||
129
+ fileContent.includes('middleware') || fileContent.includes('authenticate')) {
130
+ signals.push({ signal: 'File has authentication middleware', type: 'positive' });
131
+ confidence = 'low';
132
+ }
133
+ // Client-side indicators
134
+ if (relativePath.includes('/components/') || relativePath.includes('/pages/') ||
135
+ relativePath.includes('/app/') && !relativePath.includes('/api/')) {
136
+ signals.push({ signal: 'File appears to be client-side', type: 'negative' });
137
+ confidence = 'high';
138
+ }
139
+ question = 'Is this server-side code with proper auth middleware, or client-side code that should use RLS?';
140
+ break;
141
+ case 'secrets-localstorage':
142
+ // Check what's being stored
143
+ if (finding.code.includes('token') || finding.code.includes('jwt') ||
144
+ finding.code.includes('auth') || finding.code.includes('key')) {
145
+ signals.push({ signal: 'Storing authentication-related data', type: 'negative' });
146
+ confidence = 'high';
147
+ }
148
+ question = 'Is this storing actual auth tokens, or just non-sensitive data like UI preferences?';
149
+ break;
150
+ case 'ssrf-vulnerability':
151
+ // Check if URL is from env var
152
+ if (finding.code.includes('process.env') || finding.code.includes('env.')) {
153
+ signals.push({ signal: 'URL appears to come from environment variable', type: 'positive' });
154
+ confidence = 'low';
155
+ }
156
+ // Check for user input
157
+ if (finding.code.includes('req.') || finding.code.includes('body.') ||
158
+ finding.code.includes('params.') || finding.code.includes('query.')) {
159
+ signals.push({ signal: 'URL contains user-controlled input', type: 'negative' });
160
+ confidence = 'high';
161
+ }
162
+ question = 'Is the URL/host controlled by user input, or is it a fixed/environment-based URL?';
163
+ break;
164
+ case 'prototype-pollution':
165
+ // Check if it's just spread operator
166
+ if (finding.code.includes('...') && !finding.code.includes('merge')) {
167
+ signals.push({ signal: 'Uses spread operator (generally safe)', type: 'positive' });
168
+ confidence = 'low';
169
+ }
170
+ // Check for deep merge
171
+ if (finding.code.includes('merge') || finding.code.includes('deepmerge')) {
172
+ signals.push({ signal: 'Uses deep merge function', type: 'negative' });
173
+ confidence = 'high';
174
+ }
175
+ question = 'Is this using deep merge with user input, or just shallow spread/assign?';
176
+ break;
177
+ case 'missing-auth-route':
178
+ case 'nextjs-api-route-no-auth':
179
+ // Check for auth in file
180
+ if (fileContent.includes('getsession') || fileContent.includes('getserversession') ||
181
+ fileContent.includes('requireauth') || fileContent.includes('authenticate') ||
182
+ fileContent.includes('verifytoken') || fileContent.includes('middleware')) {
183
+ signals.push({ signal: 'File contains authentication logic', type: 'positive' });
184
+ confidence = 'low';
185
+ }
186
+ // Check if it's a public endpoint
187
+ if (relativePath.includes('login') || relativePath.includes('signup') ||
188
+ relativePath.includes('register') || relativePath.includes('public') ||
189
+ relativePath.includes('health') || relativePath.includes('webhook')) {
190
+ signals.push({ signal: 'Endpoint appears to be intentionally public', type: 'positive' });
191
+ confidence = 'low';
192
+ }
193
+ question = 'Is this endpoint intentionally public (login, webhook, health check) or should it require authentication?';
194
+ break;
195
+ case 'hardcoded-secret':
196
+ // Check if it's in a test/example file
197
+ if (relativePath.includes('test') || relativePath.includes('example') ||
198
+ relativePath.includes('sample') || relativePath.includes('mock')) {
199
+ signals.push({ signal: 'File appears to be test/example code', type: 'positive' });
200
+ confidence = 'low';
201
+ }
202
+ // Check for placeholder indicators
203
+ if (finding.code.includes('xxx') || finding.code.includes('example') ||
204
+ finding.code.includes('placeholder') || finding.code.includes('your-')) {
205
+ signals.push({ signal: 'Value appears to be a placeholder', type: 'positive' });
206
+ confidence = 'low';
207
+ }
208
+ question = 'Is this a real secret or a placeholder/example value? Check if this file is in version control.';
209
+ break;
210
+ default:
211
+ question = `Verify if this ${finding.rule.name} finding is a real security issue in your specific context.`;
212
+ }
213
+ // Add file path context
214
+ if (relativePath.includes('test') || relativePath.includes('spec') ||
215
+ relativePath.includes('mock') || relativePath.includes('fixture')) {
216
+ signals.push({ signal: 'File is in test/mock directory', type: 'positive' });
217
+ if (confidence === 'high')
218
+ confidence = 'medium';
219
+ }
220
+ if (signals.length === 0) {
221
+ signals.push({ signal: 'No additional context detected', type: 'neutral' });
222
+ }
223
+ return { signals, confidence, question };
224
+ }
225
+ function formatEnrichedFindings(findings) {
226
+ // Group by confidence
227
+ const highConf = findings.filter(f => f.confidence === 'high');
228
+ const medConf = findings.filter(f => f.confidence === 'medium');
229
+ const lowConf = findings.filter(f => f.confidence === 'low');
230
+ let output = '';
231
+ if (highConf.length > 0) {
232
+ output += `\n## 🔴 Likely Real Issues (${highConf.length})\nThese findings have high confidence and should be investigated:\n\n`;
233
+ output += highConf.map(f => formatSingleFinding(f)).join('\n---\n');
234
+ }
235
+ if (medConf.length > 0) {
236
+ output += `\n\n## 🟡 Needs Review (${medConf.length})\nThese findings need context to determine if they're issues:\n\n`;
237
+ output += medConf.map(f => formatSingleFinding(f)).join('\n---\n');
238
+ }
239
+ if (lowConf.length > 0) {
240
+ output += `\n\n## 🟢 Likely False Positives (${lowConf.length})\nThese findings appear safe based on context signals:\n\n`;
241
+ output += lowConf.map(f => formatSingleFinding(f)).join('\n---\n');
242
+ }
243
+ return output;
244
+ }
245
+ function formatSingleFinding(f) {
246
+ const signalIcons = f.contextSignals.map(s => {
247
+ const icon = s.type === 'positive' ? '✓' : s.type === 'negative' ? '⚠' : '•';
248
+ return ` ${icon} ${s.signal}`;
249
+ }).join('\n');
250
+ return `
251
+ **[${f.severity.toUpperCase()}] ${f.name}**
252
+ 📍 ${f.file}:${f.line}
253
+
254
+ \`\`\`
255
+ ${f.codeSnippet}
256
+ \`\`\`
257
+
258
+ **Context signals:**
259
+ ${signalIcons}
260
+
261
+ **🤔 Analysis needed:** ${f.analysisQuestion}
262
+
263
+ **💡 Suggested fix:** ${f.fix}
264
+ `;
265
+ }
61
266
  async function startMcpServer() {
62
267
  const server = new mcp_js_1.McpServer({
63
268
  name: 'vibeguard',
64
269
  version: '1.0.0',
65
270
  });
66
271
  // Tool: scan_code
67
- server.tool('scan_code', 'Scan files or directories for security vulnerabilities. Returns findings with severity, location, and fix suggestions. Use this after writing code or before commits.', {
272
+ server.tool('scan_code', 'Scan files or directories for security vulnerabilities. Returns findings with context analysis to help determine real issues vs false positives. After receiving results, analyze each finding based on the context signals and code snippets provided.', {
68
273
  paths: zod_1.z.array(zod_1.z.string()).describe('File or directory paths to scan (relative to current working directory)'),
69
274
  staged_only: zod_1.z.boolean().optional().describe('If true, only scan git staged files'),
70
275
  exclude: zod_1.z.array(zod_1.z.string()).optional().describe('Glob patterns to exclude (e.g., "**/vendor/**", "*.min.js")'),
@@ -85,7 +290,7 @@ async function startMcpServer() {
85
290
  content: [
86
291
  {
87
292
  type: 'text',
88
- text: `✅ No security issues found in ${result.files} file(s).\n\nGrade: A+ | Tier: ${tierLabel}`,
293
+ text: `✅ **No security issues found** in ${result.files} file(s).\n\nGrade: A+ | Tier: ${tierLabel}`,
89
294
  },
90
295
  ],
91
296
  };
@@ -97,42 +302,52 @@ async function startMcpServer() {
97
302
  low: result.findings.filter(f => f.rule.severity === 'low').length,
98
303
  };
99
304
  const grade = calculateGrade(counts);
100
- const summary = `Found ${result.findings.length} issue(s): ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low`;
101
- // Free tier: show counts only, no individual findings
305
+ // Free tier: show counts only
102
306
  if (userTier === 'free') {
103
307
  return {
104
308
  content: [
105
309
  {
106
310
  type: 'text',
107
- text: `${summary}\n\nGrade: ${grade} | Tier: ${tierLabel}\n\nUpgrade to Pro to see individual findings with file locations and fix suggestions.\nRun 'vibeguard upgrade' to unlock full scan details.`,
311
+ text: `# Security Scan Results\n\n**Found ${result.findings.length} potential issue(s):** ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low\n\n**Grade: ${grade}** | Tier: ${tierLabel}\n\nUpgrade to Pro to see detailed findings with context analysis.\nRun \`vibeguard upgrade\` to unlock.`,
108
312
  },
109
313
  ],
110
314
  };
111
315
  }
112
- // Pro tier: show full details
113
- const findings = result.findings.map(f => ({
114
- severity: f.rule.severity,
115
- rule: f.rule.id,
116
- name: f.rule.name,
117
- file: path.relative(cwd, f.file),
118
- line: f.line,
119
- message: f.rule.description,
120
- fix: f.rule.fix,
121
- isRestricted: f.isRestricted,
122
- }));
123
- const formattedFindings = findings.map(f => {
124
- const proTag = f.isRestricted ? ' [PRO]' : '';
125
- const fixLine = f.isRestricted
126
- ? ' Fix: Upgrade to Pro to see fix details'
127
- : ` Fix: ${f.fix}`;
128
- return `[${f.severity.toUpperCase()}]${proTag} ${f.file}:${f.line}\n ${f.name}\n${fixLine}`;
129
- }).join('\n\n');
130
- const footer = `\nGrade: ${grade} | Tier: ${tierLabel}`;
316
+ // Pro tier: enrich findings with context
317
+ const enrichedFindings = result.findings.map(f => {
318
+ const { signals, confidence, question } = analyzeContext(f, cwd);
319
+ return {
320
+ severity: f.rule.severity,
321
+ rule: f.rule.id,
322
+ name: f.rule.name,
323
+ file: path.relative(cwd, f.file),
324
+ line: f.line,
325
+ codeSnippet: getCodeSnippet(f.file, f.line),
326
+ contextSignals: signals,
327
+ analysisQuestion: question,
328
+ confidence,
329
+ fix: f.rule.fix || 'Review and fix as appropriate',
330
+ };
331
+ });
332
+ const highConfCount = enrichedFindings.filter(f => f.confidence === 'high').length;
333
+ const lowConfCount = enrichedFindings.filter(f => f.confidence === 'low').length;
334
+ const header = `# Security Scan Results
335
+
336
+ **Found ${result.findings.length} potential issue(s):** ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low
337
+ **Grade: ${grade}** | Tier: ${tierLabel}
338
+
339
+ **Confidence breakdown:**
340
+ - 🔴 ${highConfCount} likely real issues
341
+ - 🟢 ${lowConfCount} likely false positives
342
+
343
+ > **Instructions:** Review each finding below. Use the context signals and code snippets to determine if each is a real security issue. Focus on 🔴 high-confidence findings first.
344
+ `;
345
+ const formattedFindings = formatEnrichedFindings(enrichedFindings);
131
346
  return {
132
347
  content: [
133
348
  {
134
349
  type: 'text',
135
- text: `${summary}\n\n${formattedFindings}${footer}`,
350
+ text: header + formattedFindings,
136
351
  },
137
352
  ],
138
353
  };
@@ -173,7 +388,6 @@ async function startMcpServer() {
173
388
  language: zod_1.z.enum(['javascript', 'typescript', 'python']).describe('The programming language'),
174
389
  }, async ({ code, language }) => {
175
390
  try {
176
- const fs = await Promise.resolve().then(() => __importStar(require('fs')));
177
391
  const os = await Promise.resolve().then(() => __importStar(require('os')));
178
392
  // Create temp file
179
393
  const ext = language === 'python' ? '.py' : language === 'typescript' ? '.ts' : '.js';
@@ -192,7 +406,7 @@ async function startMcpServer() {
192
406
  content: [
193
407
  {
194
408
  type: 'text',
195
- text: `✅ No security issues found in this code snippet.\n\nGrade: A+ | Tier: ${tierLabel}`,
409
+ text: `✅ **No security issues found** in this code snippet.\n\nGrade: A+ | Tier: ${tierLabel}`,
196
410
  },
197
411
  ],
198
412
  };
@@ -204,40 +418,26 @@ async function startMcpServer() {
204
418
  low: result.findings.filter(f => f.rule.severity === 'low').length,
205
419
  };
206
420
  const grade = calculateGrade(counts);
207
- const summary = `Found ${result.findings.length} issue(s): ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low`;
208
- // Free tier: show counts only, no individual findings
421
+ // Free tier: show counts only
209
422
  if (userTier === 'free') {
210
423
  return {
211
424
  content: [
212
425
  {
213
426
  type: 'text',
214
- text: `${summary}\n\nGrade: ${grade} | Tier: ${tierLabel}\n\nUpgrade to Pro to see individual findings with line numbers and fix suggestions.`,
427
+ text: `Found ${result.findings.length} potential issue(s): ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low\n\nGrade: ${grade} | Tier: ${tierLabel}\n\nUpgrade to Pro to see details.`,
215
428
  },
216
429
  ],
217
430
  };
218
431
  }
219
- // Pro tier: show full details
220
- const findings = result.findings.map(f => ({
221
- severity: f.rule.severity,
222
- rule: f.rule.id,
223
- name: f.rule.name,
224
- line: f.line,
225
- fix: f.rule.fix,
226
- isRestricted: f.isRestricted,
227
- }));
228
- const formatted = findings.map(f => {
229
- const proTag = f.isRestricted ? ' [PRO]' : '';
230
- const fixLine = f.isRestricted
231
- ? ' Fix: Upgrade to Pro to see fix details'
232
- : ` Fix: ${f.fix}`;
233
- return `[${f.severity.toUpperCase()}]${proTag} Line ${f.line}: ${f.name}\n${fixLine}`;
432
+ // Pro tier: show findings with line numbers
433
+ const formatted = result.findings.map(f => {
434
+ return `**[${f.rule.severity.toUpperCase()}] Line ${f.line}: ${f.rule.name}**\n ${f.rule.description}\n 💡 Fix: ${f.rule.fix}`;
234
435
  }).join('\n\n');
235
- const footer = `\nGrade: ${grade} | Tier: ${tierLabel}`;
236
436
  return {
237
437
  content: [
238
438
  {
239
439
  type: 'text',
240
- text: `Found ${findings.length} issue(s):\n\n${formatted}${footer}`,
440
+ text: `# Code Snippet Security Check\n\n**Found ${result.findings.length} issue(s):** ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low\n**Grade: ${grade}** | Tier: ${tierLabel}\n\n${formatted}`,
241
441
  },
242
442
  ],
243
443
  };
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoBA,wCAqPC;AAzQD,oEAAoE;AACpE,wEAAiF;AACjF,6BAAwB;AACxB,2CAA6B;AAC7B,wCAAqC;AACrC,8DAA6D;AAC7D,4CAA+C;AAG/C,SAAS,cAAc,CAAC,MAAgC;IACtD,IAAI,MAAM,CAAC,QAAQ,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IACpC,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IAChC,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IAChC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IAClC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IAClC,IAAI,MAAM,CAAC,GAAG,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IAC/B,IAAI,MAAM,CAAC,GAAG,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IAC/B,OAAO,IAAI,CAAC;AACd,CAAC;AAEM,KAAK,UAAU,cAAc;IAClC,MAAM,MAAM,GAAG,IAAI,kBAAS,CAAC;QAC3B,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,kBAAkB;IAClB,MAAM,CAAC,IAAI,CACT,WAAW,EACX,uKAAuK,EACvK;QACE,KAAK,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,yEAAyE,CAAC;QAC9G,WAAW,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;QACnF,OAAO,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6DAA6D,CAAC;KAChH,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,EAAE;QACxC,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,IAAA,uBAAa,GAAE,CAAC;YACnC,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACxD,MAAM,OAAO,CAAC,UAAU,CAAC,UAAU,IAAI,SAAS,CAAC,CAAC;YAElD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;YAC1B,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;YAErD,MAAM,MAAM,GAAG,WAAW;gBACxB,CAAC,CAAC,MAAM,OAAO,CAAC,UAAU,EAAE;gBAC5B,CAAC,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAEhC,MAAM,QAAQ,GAAS,OAAO,CAAC,WAAW,EAAE,CAAC;YAC7C,MAAM,SAAS,GAAG,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;YAE5D,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACjC,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,iCAAiC,MAAM,CAAC,KAAK,kCAAkC,SAAS,EAAE;yBACjG;qBACF;iBACF,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,GAA6B;gBACvC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,MAAM;gBAC5E,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,MAAM;gBACpE,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,MAAM;gBACxE,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC,MAAM;aACnE,CAAC;YAEF,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;YACrC,MAAM,OAAO,GAAG,SAAS,MAAM,CAAC,QAAQ,CAAC,MAAM,cAAc,MAAM,CAAC,QAAQ,cAAc,MAAM,CAAC,IAAI,UAAU,MAAM,CAAC,MAAM,YAAY,MAAM,CAAC,GAAG,MAAM,CAAC;YAEzJ,sDAAsD;YACtD,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;gBACxB,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,GAAG,OAAO,cAAc,KAAK,YAAY,SAAS,8IAA8I;yBACvM;qBACF;iBACF,CAAC;YACJ,CAAC;YAED,8BAA8B;YAC9B,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACzC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ;gBACzB,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE;gBACf,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI;gBACjB,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC;gBAChC,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW;gBAC3B,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG;gBACf,YAAY,EAAE,CAAC,CAAC,YAAY;aAC7B,CAAC,CAAC,CAAC;YAEJ,MAAM,iBAAiB,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;gBACzC,MAAM,MAAM,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC9C,MAAM,OAAO,GAAG,CAAC,CAAC,YAAY;oBAC5B,CAAC,CAAC,0CAA0C;oBAC5C,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,EAAE,CAAC;gBACtB,OAAO,IAAI,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,IAAI,MAAM,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC/F,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAEhB,MAAM,MAAM,GAAG,YAAY,KAAK,YAAY,SAAS,EAAE,CAAC;YAExD,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,GAAG,OAAO,OAAO,iBAAiB,GAAG,MAAM,EAAE;qBACpD;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,mBAAmB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE;qBACpF;iBACF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,4BAA4B;IAC5B,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,wHAAwH,EACxH;QACE,QAAQ,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;KACxG,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrB,IAAI,KAAK,GAAG,2BAAa,CAAC;QAE1B,IAAI,QAAQ,EAAE,CAAC;YACb,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;QACrD,CAAC;QAED,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAC9B,IAAI,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,WAAW,kBAAkB,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACjH,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAEf,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,GAAG,KAAK,CAAC,MAAM,yBAAyB,SAAS,EAAE;iBAC1D;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,2BAA2B;IAC3B,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,6HAA6H,EAC7H;QACE,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;QACtD,QAAQ,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,0BAA0B,CAAC;KAC9F,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC3B,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,wDAAa,IAAI,GAAC,CAAC;YAC9B,MAAM,EAAE,GAAG,wDAAa,IAAI,GAAC,CAAC;YAE9B,mBAAmB;YACnB,MAAM,GAAG,GAAG,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;YACtF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,mBAAmB,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,EAAE,CAAC,CAAC;YAE/E,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAEjC,MAAM,UAAU,GAAG,IAAA,uBAAa,GAAE,CAAC;YACnC,MAAM,OAAO,GAAG,IAAI,iBAAO,EAAE,CAAC;YAC9B,MAAM,OAAO,CAAC,UAAU,CAAC,UAAU,IAAI,SAAS,CAAC,CAAC;YAElD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC9C,MAAM,QAAQ,GAAS,OAAO,CAAC,WAAW,EAAE,CAAC;YAC7C,MAAM,SAAS,GAAG,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;YAE5D,WAAW;YACX,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YAExB,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACjC,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,yEAAyE,SAAS,EAAE;yBAC3F;qBACF;iBACF,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,GAA6B;gBACvC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,MAAM;gBAC5E,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,MAAM;gBACpE,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,MAAM;gBACxE,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC,MAAM;aACnE,CAAC;YAEF,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;YACrC,MAAM,OAAO,GAAG,SAAS,MAAM,CAAC,QAAQ,CAAC,MAAM,cAAc,MAAM,CAAC,QAAQ,cAAc,MAAM,CAAC,IAAI,UAAU,MAAM,CAAC,MAAM,YAAY,MAAM,CAAC,GAAG,MAAM,CAAC;YAEzJ,sDAAsD;YACtD,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;gBACxB,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,GAAG,OAAO,cAAc,KAAK,YAAY,SAAS,sFAAsF;yBAC/I;qBACF;iBACF,CAAC;YACJ,CAAC;YAED,8BAA8B;YAC9B,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACzC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ;gBACzB,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE;gBACf,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI;gBACjB,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG;gBACf,YAAY,EAAE,CAAC,CAAC,YAAY;aAC7B,CAAC,CAAC,CAAC;YAEJ,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;gBACjC,MAAM,MAAM,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC9C,MAAM,OAAO,GAAG,CAAC,CAAC,YAAY;oBAC5B,CAAC,CAAC,0CAA0C;oBAC5C,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,EAAE,CAAC;gBACtB,OAAO,IAAI,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,IAAI,MAAM,SAAS,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YACxF,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAEhB,MAAM,MAAM,GAAG,YAAY,KAAK,YAAY,SAAS,EAAE,CAAC;YAExD,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,SAAS,QAAQ,CAAC,MAAM,iBAAiB,SAAS,GAAG,MAAM,EAAE;qBACpE;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,wBAAwB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE;qBACzF;iBACF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,oBAAoB;IACpB,MAAM,SAAS,GAAG,IAAI,+BAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indicated/vibeguard",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "Local CLI security scanner for AI-generated code",
5
5
  "main": "dist/cli/index.js",
6
6
  "bin": {
package/src/mcp/server.ts CHANGED
@@ -2,10 +2,11 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
3
  import { z } from 'zod';
4
4
  import * as path from 'path';
5
+ import * as fs from 'fs';
5
6
  import { Scanner } from '../scanner';
6
7
  import { securityRules } from '../scanner/rules/definitions';
7
8
  import { getLicenseKey } from '../api/license';
8
- import { Severity, Tier } from '../types';
9
+ import { Severity, Tier, Finding } from '../types';
9
10
 
10
11
  function calculateGrade(counts: Record<Severity, number>): string {
11
12
  if (counts.critical > 0) return 'F';
@@ -18,6 +19,249 @@ function calculateGrade(counts: Record<Severity, number>): string {
18
19
  return 'A+';
19
20
  }
20
21
 
22
+ interface ContextSignal {
23
+ signal: string;
24
+ type: 'positive' | 'negative' | 'neutral';
25
+ }
26
+
27
+ interface EnrichedFinding {
28
+ severity: string;
29
+ rule: string;
30
+ name: string;
31
+ file: string;
32
+ line: number;
33
+ codeSnippet: string;
34
+ contextSignals: ContextSignal[];
35
+ analysisQuestion: string;
36
+ confidence: 'high' | 'medium' | 'low';
37
+ fix: string;
38
+ }
39
+
40
+ function getCodeSnippet(filePath: string, line: number, contextLines: number = 3): string {
41
+ try {
42
+ const content = fs.readFileSync(filePath, 'utf-8');
43
+ const lines = content.split('\n');
44
+ const startLine = Math.max(0, line - contextLines - 1);
45
+ const endLine = Math.min(lines.length, line + contextLines);
46
+
47
+ return lines.slice(startLine, endLine).map((l, i) => {
48
+ const lineNum = startLine + i + 1;
49
+ const marker = lineNum === line ? '→' : ' ';
50
+ return `${marker} ${lineNum.toString().padStart(4)}: ${l}`;
51
+ }).join('\n');
52
+ } catch {
53
+ return '(Could not read file)';
54
+ }
55
+ }
56
+
57
+ function analyzeContext(finding: Finding, cwd: string): { signals: ContextSignal[], confidence: 'high' | 'medium' | 'low', question: string } {
58
+ const signals: ContextSignal[] = [];
59
+ let confidence: 'high' | 'medium' | 'low' = 'high';
60
+ let question = '';
61
+
62
+ const filePath = finding.file;
63
+ const relativePath = path.relative(cwd, filePath).toLowerCase();
64
+
65
+ // Read file content for analysis
66
+ let fileContent = '';
67
+ try {
68
+ fileContent = fs.readFileSync(filePath, 'utf-8').toLowerCase();
69
+ } catch {
70
+ // Can't read file
71
+ }
72
+
73
+ // Analyze based on rule type
74
+ switch (finding.rule.id) {
75
+ case 'xss-innerhtml':
76
+ // Check for sanitizer imports
77
+ if (fileContent.includes('dompurify') || fileContent.includes('sanitize') ||
78
+ fileContent.includes('escapehtml') || fileContent.includes('escape-html')) {
79
+ signals.push({ signal: 'File imports sanitization library', type: 'positive' });
80
+ confidence = 'low';
81
+ }
82
+ // Check if it's static HTML
83
+ if (finding.code.includes("'<") || finding.code.includes('"<') || finding.code.includes('`<')) {
84
+ signals.push({ signal: 'Appears to be static HTML string', type: 'positive' });
85
+ confidence = 'low';
86
+ }
87
+ // Check for user input indicators
88
+ if (finding.code.includes('user') || finding.code.includes('input') ||
89
+ finding.code.includes('req.') || finding.code.includes('params')) {
90
+ signals.push({ signal: 'May contain user-controlled input', type: 'negative' });
91
+ confidence = 'high';
92
+ }
93
+ question = 'Is the data being inserted sanitized before this line? Check if escapeHtml() or similar is called on the variable.';
94
+ break;
95
+
96
+ case 'supabase-no-rls':
97
+ // Check if it's server-side
98
+ if (relativePath.includes('/api/') || relativePath.includes('/server/') ||
99
+ relativePath.includes('/routes/') || relativePath.includes('/backend/')) {
100
+ signals.push({ signal: 'File is in server-side directory', type: 'positive' });
101
+ confidence = 'low';
102
+ }
103
+ // Check for service role key
104
+ if (fileContent.includes('service_role') || fileContent.includes('servicerole') ||
105
+ fileContent.includes('supabase_service')) {
106
+ signals.push({ signal: 'Uses service role key (server-side pattern)', type: 'positive' });
107
+ confidence = 'low';
108
+ }
109
+ // Check for auth middleware
110
+ if (fileContent.includes('requireauth') || fileContent.includes('requireadmin') ||
111
+ fileContent.includes('middleware') || fileContent.includes('authenticate')) {
112
+ signals.push({ signal: 'File has authentication middleware', type: 'positive' });
113
+ confidence = 'low';
114
+ }
115
+ // Client-side indicators
116
+ if (relativePath.includes('/components/') || relativePath.includes('/pages/') ||
117
+ relativePath.includes('/app/') && !relativePath.includes('/api/')) {
118
+ signals.push({ signal: 'File appears to be client-side', type: 'negative' });
119
+ confidence = 'high';
120
+ }
121
+ question = 'Is this server-side code with proper auth middleware, or client-side code that should use RLS?';
122
+ break;
123
+
124
+ case 'secrets-localstorage':
125
+ // Check what's being stored
126
+ if (finding.code.includes('token') || finding.code.includes('jwt') ||
127
+ finding.code.includes('auth') || finding.code.includes('key')) {
128
+ signals.push({ signal: 'Storing authentication-related data', type: 'negative' });
129
+ confidence = 'high';
130
+ }
131
+ question = 'Is this storing actual auth tokens, or just non-sensitive data like UI preferences?';
132
+ break;
133
+
134
+ case 'ssrf-vulnerability':
135
+ // Check if URL is from env var
136
+ if (finding.code.includes('process.env') || finding.code.includes('env.')) {
137
+ signals.push({ signal: 'URL appears to come from environment variable', type: 'positive' });
138
+ confidence = 'low';
139
+ }
140
+ // Check for user input
141
+ if (finding.code.includes('req.') || finding.code.includes('body.') ||
142
+ finding.code.includes('params.') || finding.code.includes('query.')) {
143
+ signals.push({ signal: 'URL contains user-controlled input', type: 'negative' });
144
+ confidence = 'high';
145
+ }
146
+ question = 'Is the URL/host controlled by user input, or is it a fixed/environment-based URL?';
147
+ break;
148
+
149
+ case 'prototype-pollution':
150
+ // Check if it's just spread operator
151
+ if (finding.code.includes('...') && !finding.code.includes('merge')) {
152
+ signals.push({ signal: 'Uses spread operator (generally safe)', type: 'positive' });
153
+ confidence = 'low';
154
+ }
155
+ // Check for deep merge
156
+ if (finding.code.includes('merge') || finding.code.includes('deepmerge')) {
157
+ signals.push({ signal: 'Uses deep merge function', type: 'negative' });
158
+ confidence = 'high';
159
+ }
160
+ question = 'Is this using deep merge with user input, or just shallow spread/assign?';
161
+ break;
162
+
163
+ case 'missing-auth-route':
164
+ case 'nextjs-api-route-no-auth':
165
+ // Check for auth in file
166
+ if (fileContent.includes('getsession') || fileContent.includes('getserversession') ||
167
+ fileContent.includes('requireauth') || fileContent.includes('authenticate') ||
168
+ fileContent.includes('verifytoken') || fileContent.includes('middleware')) {
169
+ signals.push({ signal: 'File contains authentication logic', type: 'positive' });
170
+ confidence = 'low';
171
+ }
172
+ // Check if it's a public endpoint
173
+ if (relativePath.includes('login') || relativePath.includes('signup') ||
174
+ relativePath.includes('register') || relativePath.includes('public') ||
175
+ relativePath.includes('health') || relativePath.includes('webhook')) {
176
+ signals.push({ signal: 'Endpoint appears to be intentionally public', type: 'positive' });
177
+ confidence = 'low';
178
+ }
179
+ question = 'Is this endpoint intentionally public (login, webhook, health check) or should it require authentication?';
180
+ break;
181
+
182
+ case 'hardcoded-secret':
183
+ // Check if it's in a test/example file
184
+ if (relativePath.includes('test') || relativePath.includes('example') ||
185
+ relativePath.includes('sample') || relativePath.includes('mock')) {
186
+ signals.push({ signal: 'File appears to be test/example code', type: 'positive' });
187
+ confidence = 'low';
188
+ }
189
+ // Check for placeholder indicators
190
+ if (finding.code.includes('xxx') || finding.code.includes('example') ||
191
+ finding.code.includes('placeholder') || finding.code.includes('your-')) {
192
+ signals.push({ signal: 'Value appears to be a placeholder', type: 'positive' });
193
+ confidence = 'low';
194
+ }
195
+ question = 'Is this a real secret or a placeholder/example value? Check if this file is in version control.';
196
+ break;
197
+
198
+ default:
199
+ question = `Verify if this ${finding.rule.name} finding is a real security issue in your specific context.`;
200
+ }
201
+
202
+ // Add file path context
203
+ if (relativePath.includes('test') || relativePath.includes('spec') ||
204
+ relativePath.includes('mock') || relativePath.includes('fixture')) {
205
+ signals.push({ signal: 'File is in test/mock directory', type: 'positive' });
206
+ if (confidence === 'high') confidence = 'medium';
207
+ }
208
+
209
+ if (signals.length === 0) {
210
+ signals.push({ signal: 'No additional context detected', type: 'neutral' });
211
+ }
212
+
213
+ return { signals, confidence, question };
214
+ }
215
+
216
+ function formatEnrichedFindings(findings: EnrichedFinding[]): string {
217
+ // Group by confidence
218
+ const highConf = findings.filter(f => f.confidence === 'high');
219
+ const medConf = findings.filter(f => f.confidence === 'medium');
220
+ const lowConf = findings.filter(f => f.confidence === 'low');
221
+
222
+ let output = '';
223
+
224
+ if (highConf.length > 0) {
225
+ output += `\n## 🔴 Likely Real Issues (${highConf.length})\nThese findings have high confidence and should be investigated:\n\n`;
226
+ output += highConf.map(f => formatSingleFinding(f)).join('\n---\n');
227
+ }
228
+
229
+ if (medConf.length > 0) {
230
+ output += `\n\n## 🟡 Needs Review (${medConf.length})\nThese findings need context to determine if they're issues:\n\n`;
231
+ output += medConf.map(f => formatSingleFinding(f)).join('\n---\n');
232
+ }
233
+
234
+ if (lowConf.length > 0) {
235
+ output += `\n\n## 🟢 Likely False Positives (${lowConf.length})\nThese findings appear safe based on context signals:\n\n`;
236
+ output += lowConf.map(f => formatSingleFinding(f)).join('\n---\n');
237
+ }
238
+
239
+ return output;
240
+ }
241
+
242
+ function formatSingleFinding(f: EnrichedFinding): string {
243
+ const signalIcons = f.contextSignals.map(s => {
244
+ const icon = s.type === 'positive' ? '✓' : s.type === 'negative' ? '⚠' : '•';
245
+ return ` ${icon} ${s.signal}`;
246
+ }).join('\n');
247
+
248
+ return `
249
+ **[${f.severity.toUpperCase()}] ${f.name}**
250
+ 📍 ${f.file}:${f.line}
251
+
252
+ \`\`\`
253
+ ${f.codeSnippet}
254
+ \`\`\`
255
+
256
+ **Context signals:**
257
+ ${signalIcons}
258
+
259
+ **🤔 Analysis needed:** ${f.analysisQuestion}
260
+
261
+ **💡 Suggested fix:** ${f.fix}
262
+ `;
263
+ }
264
+
21
265
  export async function startMcpServer(): Promise<void> {
22
266
  const server = new McpServer({
23
267
  name: 'vibeguard',
@@ -27,7 +271,7 @@ export async function startMcpServer(): Promise<void> {
27
271
  // Tool: scan_code
28
272
  server.tool(
29
273
  'scan_code',
30
- 'Scan files or directories for security vulnerabilities. Returns findings with severity, location, and fix suggestions. Use this after writing code or before commits.',
274
+ 'Scan files or directories for security vulnerabilities. Returns findings with context analysis to help determine real issues vs false positives. After receiving results, analyze each finding based on the context signals and code snippets provided.',
31
275
  {
32
276
  paths: z.array(z.string()).describe('File or directory paths to scan (relative to current working directory)'),
33
277
  staged_only: z.boolean().optional().describe('If true, only scan git staged files'),
@@ -54,7 +298,7 @@ export async function startMcpServer(): Promise<void> {
54
298
  content: [
55
299
  {
56
300
  type: 'text' as const,
57
- text: `✅ No security issues found in ${result.files} file(s).\n\nGrade: A+ | Tier: ${tierLabel}`,
301
+ text: `✅ **No security issues found** in ${result.files} file(s).\n\nGrade: A+ | Tier: ${tierLabel}`,
58
302
  },
59
303
  ],
60
304
  };
@@ -68,47 +312,58 @@ export async function startMcpServer(): Promise<void> {
68
312
  };
69
313
 
70
314
  const grade = calculateGrade(counts);
71
- const summary = `Found ${result.findings.length} issue(s): ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low`;
72
315
 
73
- // Free tier: show counts only, no individual findings
316
+ // Free tier: show counts only
74
317
  if (userTier === 'free') {
75
318
  return {
76
319
  content: [
77
320
  {
78
321
  type: 'text' as const,
79
- text: `${summary}\n\nGrade: ${grade} | Tier: ${tierLabel}\n\nUpgrade to Pro to see individual findings with file locations and fix suggestions.\nRun 'vibeguard upgrade' to unlock full scan details.`,
322
+ text: `# Security Scan Results\n\n**Found ${result.findings.length} potential issue(s):** ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low\n\n**Grade: ${grade}** | Tier: ${tierLabel}\n\nUpgrade to Pro to see detailed findings with context analysis.\nRun \`vibeguard upgrade\` to unlock.`,
80
323
  },
81
324
  ],
82
325
  };
83
326
  }
84
327
 
85
- // Pro tier: show full details
86
- const findings = result.findings.map(f => ({
87
- severity: f.rule.severity,
88
- rule: f.rule.id,
89
- name: f.rule.name,
90
- file: path.relative(cwd, f.file),
91
- line: f.line,
92
- message: f.rule.description,
93
- fix: f.rule.fix,
94
- isRestricted: f.isRestricted,
95
- }));
96
-
97
- const formattedFindings = findings.map(f => {
98
- const proTag = f.isRestricted ? ' [PRO]' : '';
99
- const fixLine = f.isRestricted
100
- ? ' Fix: Upgrade to Pro to see fix details'
101
- : ` Fix: ${f.fix}`;
102
- return `[${f.severity.toUpperCase()}]${proTag} ${f.file}:${f.line}\n ${f.name}\n${fixLine}`;
103
- }).join('\n\n');
328
+ // Pro tier: enrich findings with context
329
+ const enrichedFindings: EnrichedFinding[] = result.findings.map(f => {
330
+ const { signals, confidence, question } = analyzeContext(f, cwd);
331
+ return {
332
+ severity: f.rule.severity,
333
+ rule: f.rule.id,
334
+ name: f.rule.name,
335
+ file: path.relative(cwd, f.file),
336
+ line: f.line,
337
+ codeSnippet: getCodeSnippet(f.file, f.line),
338
+ contextSignals: signals,
339
+ analysisQuestion: question,
340
+ confidence,
341
+ fix: f.rule.fix || 'Review and fix as appropriate',
342
+ };
343
+ });
104
344
 
105
- const footer = `\nGrade: ${grade} | Tier: ${tierLabel}`;
345
+ const highConfCount = enrichedFindings.filter(f => f.confidence === 'high').length;
346
+ const lowConfCount = enrichedFindings.filter(f => f.confidence === 'low').length;
347
+
348
+ const header = `# Security Scan Results
349
+
350
+ **Found ${result.findings.length} potential issue(s):** ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low
351
+ **Grade: ${grade}** | Tier: ${tierLabel}
352
+
353
+ **Confidence breakdown:**
354
+ - 🔴 ${highConfCount} likely real issues
355
+ - 🟢 ${lowConfCount} likely false positives
356
+
357
+ > **Instructions:** Review each finding below. Use the context signals and code snippets to determine if each is a real security issue. Focus on 🔴 high-confidence findings first.
358
+ `;
359
+
360
+ const formattedFindings = formatEnrichedFindings(enrichedFindings);
106
361
 
107
362
  return {
108
363
  content: [
109
364
  {
110
365
  type: 'text' as const,
111
- text: `${summary}\n\n${formattedFindings}${footer}`,
366
+ text: header + formattedFindings,
112
367
  },
113
368
  ],
114
369
  };
@@ -165,7 +420,6 @@ export async function startMcpServer(): Promise<void> {
165
420
  },
166
421
  async ({ code, language }) => {
167
422
  try {
168
- const fs = await import('fs');
169
423
  const os = await import('os');
170
424
 
171
425
  // Create temp file
@@ -190,7 +444,7 @@ export async function startMcpServer(): Promise<void> {
190
444
  content: [
191
445
  {
192
446
  type: 'text' as const,
193
- text: `✅ No security issues found in this code snippet.\n\nGrade: A+ | Tier: ${tierLabel}`,
447
+ text: `✅ **No security issues found** in this code snippet.\n\nGrade: A+ | Tier: ${tierLabel}`,
194
448
  },
195
449
  ],
196
450
  };
@@ -204,45 +458,29 @@ export async function startMcpServer(): Promise<void> {
204
458
  };
205
459
 
206
460
  const grade = calculateGrade(counts);
207
- const summary = `Found ${result.findings.length} issue(s): ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low`;
208
461
 
209
- // Free tier: show counts only, no individual findings
462
+ // Free tier: show counts only
210
463
  if (userTier === 'free') {
211
464
  return {
212
465
  content: [
213
466
  {
214
467
  type: 'text' as const,
215
- text: `${summary}\n\nGrade: ${grade} | Tier: ${tierLabel}\n\nUpgrade to Pro to see individual findings with line numbers and fix suggestions.`,
468
+ text: `Found ${result.findings.length} potential issue(s): ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low\n\nGrade: ${grade} | Tier: ${tierLabel}\n\nUpgrade to Pro to see details.`,
216
469
  },
217
470
  ],
218
471
  };
219
472
  }
220
473
 
221
- // Pro tier: show full details
222
- const findings = result.findings.map(f => ({
223
- severity: f.rule.severity,
224
- rule: f.rule.id,
225
- name: f.rule.name,
226
- line: f.line,
227
- fix: f.rule.fix,
228
- isRestricted: f.isRestricted,
229
- }));
230
-
231
- const formatted = findings.map(f => {
232
- const proTag = f.isRestricted ? ' [PRO]' : '';
233
- const fixLine = f.isRestricted
234
- ? ' Fix: Upgrade to Pro to see fix details'
235
- : ` Fix: ${f.fix}`;
236
- return `[${f.severity.toUpperCase()}]${proTag} Line ${f.line}: ${f.name}\n${fixLine}`;
474
+ // Pro tier: show findings with line numbers
475
+ const formatted = result.findings.map(f => {
476
+ return `**[${f.rule.severity.toUpperCase()}] Line ${f.line}: ${f.rule.name}**\n ${f.rule.description}\n 💡 Fix: ${f.rule.fix}`;
237
477
  }).join('\n\n');
238
478
 
239
- const footer = `\nGrade: ${grade} | Tier: ${tierLabel}`;
240
-
241
479
  return {
242
480
  content: [
243
481
  {
244
482
  type: 'text' as const,
245
- text: `Found ${findings.length} issue(s):\n\n${formatted}${footer}`,
483
+ text: `# Code Snippet Security Check\n\n**Found ${result.findings.length} issue(s):** ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low\n**Grade: ${grade}** | Tier: ${tierLabel}\n\n${formatted}`,
246
484
  },
247
485
  ],
248
486
  };