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
JavaScript
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