UNPKG

ai-debug-local-mcp

Version:

🎯 ENHANCED AI GUIDANCE v4.1.2: Dramatically improved tool descriptions help AI users choose the right tools instead of 'close enough' options. Ultra-fast keyboard automation (10x speed), universal recording, multi-ecosystem debugging support, and compreh

177 lines 7.54 kB
import { BaseToolHandler } from '../base-handler.js'; /** * Handler for Next.js security audit tool */ export class NextJSSecurityHandler extends BaseToolHandler { nextjsEngine; constructor(nextjsEngine) { super(); this.nextjsEngine = nextjsEngine; } tools = [ { name: 'nextjs_security_audit', description: 'Audit Next.js security including environment variable exposure, security headers, and CORS configuration.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } } ]; async handle(toolName, args, sessions) { const session = sessions.get(args.sessionId); if (!session) { throw new Error(`Debug session ${args.sessionId} not found`); } // Validate this is a Next.js app if (session.framework !== 'nextjs' && session.framework !== 'next' && !(session.framework === 'react' && session.isNextJS)) { throw new Error('This tool only works with Next.js applications'); } if (toolName === 'nextjs_security_audit') { return this.auditSecurity(args, session); } throw new Error(`Unknown Next.js security tool: ${toolName}`); } async auditSecurity(args, session) { try { const security = await this.nextjsEngine.getSecurityAnalysis(); let content = '🔒 **Next.js Security Audit**\n\n'; // Calculate security score let score = 100; const issues = []; // Check environment variables const exposedNonPublic = security.environmentVariables.exposed.filter((v) => !v.startsWith('NEXT_PUBLIC_') && v !== 'NODE_ENV'); if (exposedNonPublic.length > 0) { score -= 30; issues.push(`${exposedNonPublic.length} non-public env vars exposed`); } // Check security headers if (!security.headers.csp) { score -= 15; issues.push('Missing Content-Security-Policy'); } if (!security.headers.xFrameOptions) { score -= 10; issues.push('Missing X-Frame-Options'); } if (!security.headers.permissionsPolicy) { score -= 10; issues.push('Missing Permissions-Policy'); } if (security.headers.cors === '*') { score -= 15; issues.push('Wildcard CORS origin'); } // Security score summary content += `### 🎯 Security Score: ${score}/100\n\n`; if (score === 100) { content += '✅ **Excellent security configuration!**\n\n'; } else if (score >= 80) { content += '⚠️ **Good security with minor issues**\n\n'; } else if (score >= 60) { content += '🟠 **Moderate security concerns**\n\n'; } else { content += '🔴 **Critical security issues detected**\n\n'; } if (issues.length > 0) { content += '### Issues Found:\n'; issues.forEach(issue => { content += `- ${issue}\n`; }); content += '\n'; } // Environment Variables Analysis content += '### 🔑 Environment Variables\n\n'; if (exposedNonPublic.length > 0) { content += '⚠️ **Non-public variables exposed to client:**\n'; exposedNonPublic.forEach((v) => { content += `- ${v}\n`; }); content += '\n**Recommendation:** Only expose NEXT_PUBLIC_* variables to the client.\n\n'; } else { content += '✅ No sensitive environment variables exposed\n\n'; } content += `**Properly prefixed variables:** ${security.environmentVariables.properlyPrefixed.length}\n`; content += `**Total exposed variables:** ${security.environmentVariables.exposed.length}\n\n`; // Security Headers content += '### 🛡️ Security Headers\n\n'; content += this.formatSecurityHeader('Content-Security-Policy', security.headers.csp); content += this.formatSecurityHeader('X-Frame-Options', security.headers.xFrameOptions); content += this.formatSecurityHeader('Permissions-Policy', security.headers.permissionsPolicy); // CORS Configuration content += '### 🌐 CORS Configuration\n\n'; if (security.headers.cors) { if (security.headers.cors === '*') { content += '⚠️ **Wildcard CORS origin detected**\n'; content += 'This allows any website to make requests to your API.\n'; content += 'Consider restricting to specific origins.\n'; } else { content += `✅ CORS restricted to: ${security.headers.cors}\n`; } } else { content += '✅ CORS not configured (same-origin only)\n'; } content += '\n'; // Add missing headers info if available if (security.headers.missingHeaders && security.headers.missingHeaders.length > 0) { content += '### ⚠️ Missing Security Headers\n\n'; security.headers.missingHeaders.forEach((header) => { content += `- ${header}\n`; }); content += '\n'; } // Recommendations content += '### 📋 Recommendations\n\n'; content += this.getSecurityRecommendations(security, score); return { content: [{ type: 'text', text: content.trim() }] }; } catch (error) { throw new Error(`Failed to audit security: ${error instanceof Error ? error.message : String(error)}`); } } formatSecurityHeader(name, value) { if (value === true) { return `✅ **${name}**: Enabled\n`; } else if (typeof value === 'string' && value) { return `✅ **${name}**: ${value}\n`; } else { return `❌ **${name}**: Not set\n`; } } getSecurityRecommendations(security, score) { const recommendations = []; if (!security.headers.csp) { recommendations.push('1. **Add Content-Security-Policy header** to prevent XSS attacks'); } if (!security.headers.permissionsPolicy) { recommendations.push('2. **Add Permissions-Policy header** to control browser features'); } if (security.headers.cors === '*') { recommendations.push('3. **Restrict CORS origins** to specific domains'); } if (recommendations.length === 0) { return '✅ Your security configuration follows best practices!\n'; } return recommendations.join('\n') + '\n'; } } //# sourceMappingURL=nextjs-security-handler.js.map