Skip to main content
Glama
securityHeaders.ts12.4 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; import axios from "axios"; import { AuthManager } from "../utils/authManager.js"; /** * Register security headers testing tools */ export function registerSecurityHeadersTools(server: McpServer) { // Security headers check server.tool( "security_headers_check", { endpoint: z.string().url().describe("API endpoint to test"), http_method: z.enum(["GET", "HEAD", "OPTIONS"]).default("GET").describe("HTTP method to use"), use_auth: z.boolean().default(true).describe("Whether to use current authentication if available"), }, async ({ endpoint, http_method, use_auth }) => { try { // Get auth headers if available and requested let headers = {}; if (use_auth) { const authManager = AuthManager.getInstance(); const authState = authManager.getAuthState(); if (authState.type !== 'none' && authState.headers) { headers = { ...headers, ...authState.headers }; } } // Make the request const response = await axios({ method: http_method.toLowerCase(), url: endpoint, headers, validateStatus: () => true, // Accept any status code }); // Get headers (case insensitive) const responseHeaders = response.headers; const headerMap = new Map<string, string>(); for (const key in responseHeaders) { headerMap.set(key.toLowerCase(), responseHeaders[key]); } // Check for security headers const securityHeaders = checkSecurityHeaders(headerMap); // Generate recommendations const recommendations = generateRecommendations(securityHeaders); // Add authentication info to the report const authManager = AuthManager.getInstance(); const authState = authManager.getAuthState(); const authInfo = use_auth && authState.type !== 'none' ? `\nTest performed with authentication: ${authState.type}` : '\nTest performed without authentication'; return { content: [ { type: "text", text: formatSecurityHeadersReport(securityHeaders, recommendations, endpoint, authInfo), }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error checking security headers: ${(error as Error).message}`, }, ], }; } } ); } /** * Check for security headers in response */ function checkSecurityHeaders(headers: Map<string, string>): Array<{ name: string; present: boolean; value: string; description: string; severity: "High" | "Medium" | "Low"; recommendation: string; }> { return [ { name: "Strict-Transport-Security", present: headers.has("strict-transport-security"), value: headers.get("strict-transport-security") || "", description: "Ensures the browser only uses HTTPS for the domain", severity: "High", recommendation: headers.has("strict-transport-security") ? (headers.get("strict-transport-security")?.includes("max-age=31536000") ? "Good: HSTS is properly configured" : "Improve: Set max-age to at least one year (31536000)") : "Add: Strict-Transport-Security: max-age=31536000; includeSubDomains", }, { name: "Content-Security-Policy", present: headers.has("content-security-policy"), value: headers.get("content-security-policy") || "", description: "Controls which resources the browser is allowed to load", severity: "High", recommendation: headers.has("content-security-policy") ? "Verify that the CSP policy is restrictive enough for your application" : "Add a Content-Security-Policy header appropriate for your application", }, { name: "X-Content-Type-Options", present: headers.has("x-content-type-options"), value: headers.get("x-content-type-options") || "", description: "Prevents the browser from MIME-sniffing content types", severity: "Medium", recommendation: headers.has("x-content-type-options") ? (headers.get("x-content-type-options") === "nosniff" ? "Good: X-Content-Type-Options is properly configured" : "Fix: Set X-Content-Type-Options to 'nosniff'") : "Add: X-Content-Type-Options: nosniff", }, { name: "X-Frame-Options", present: headers.has("x-frame-options"), value: headers.get("x-frame-options") || "", description: "Prevents your site from being embedded in iframes on other sites", severity: "Medium", recommendation: headers.has("x-frame-options") ? (["DENY", "SAMEORIGIN"].includes(headers.get("x-frame-options")?.toUpperCase() || "") ? "Good: X-Frame-Options is properly configured" : "Fix: Set X-Frame-Options to 'DENY' or 'SAMEORIGIN'") : "Add: X-Frame-Options: DENY", }, { name: "X-XSS-Protection", present: headers.has("x-xss-protection"), value: headers.get("x-xss-protection") || "", description: "Enables browser's built-in XSS filtering", severity: "Low", recommendation: headers.has("x-xss-protection") ? (headers.get("x-xss-protection") === "1; mode=block" ? "Good: X-XSS-Protection is properly configured" : "Improve: Set X-XSS-Protection to '1; mode=block'") : "Add: X-XSS-Protection: 1; mode=block", }, { name: "Referrer-Policy", present: headers.has("referrer-policy"), value: headers.get("referrer-policy") || "", description: "Controls how much referrer information is included with requests", severity: "Medium", recommendation: headers.has("referrer-policy") ? "Verify that the referrer policy is appropriate for your application" : "Add a Referrer-Policy header (e.g., 'strict-origin-when-cross-origin')", }, { name: "Permissions-Policy", present: headers.has("permissions-policy") || headers.has("feature-policy"), value: headers.get("permissions-policy") || headers.get("feature-policy") || "", description: "Controls which browser features can be used by the page", severity: "Medium", recommendation: headers.has("permissions-policy") || headers.has("feature-policy") ? "Verify that the permissions policy is appropriate for your application" : "Add a Permissions-Policy header to restrict access to browser features", }, { name: "Cache-Control", present: headers.has("cache-control"), value: headers.get("cache-control") || "", description: "Controls how responses are cached", severity: "Medium", recommendation: headers.has("cache-control") ? (headers.get("cache-control")?.includes("no-store") ? "Good: Cache-Control prevents storage of sensitive data" : "Consider: For sensitive data, use 'Cache-Control: no-store'") : "Add appropriate Cache-Control header based on content sensitivity", }, { name: "X-Permitted-Cross-Domain-Policies", present: headers.has("x-permitted-cross-domain-policies"), value: headers.get("x-permitted-cross-domain-policies") || "", description: "Controls Adobe Flash and PDF client resource sharing", severity: "Low", recommendation: headers.has("x-permitted-cross-domain-policies") ? "Verify that the policy is appropriate for your application" : "Consider adding: X-Permitted-Cross-Domain-Policies: none", }, { name: "Access-Control-Allow-Origin", present: headers.has("access-control-allow-origin"), value: headers.get("access-control-allow-origin") || "", description: "Controls which domains can access the API via CORS", severity: "High", recommendation: headers.has("access-control-allow-origin") ? (headers.get("access-control-allow-origin") === "*" ? "Warning: CORS is enabled for all origins" : "Verify that CORS is correctly configured for your use case") : "CORS not enabled - appropriate if this API should not be accessed cross-origin", }, ]; } /** * Generate overall recommendations based on security headers */ function generateRecommendations( securityHeaders: Array<{ name: string; present: boolean; value: string; description: string; severity: "High" | "Medium" | "Low"; recommendation: string; }> ): string[] { const recommendations: string[] = []; // Count missing headers by severity const missingHigh = securityHeaders.filter(h => !h.present && h.severity === "High").length; const missingMedium = securityHeaders.filter(h => !h.present && h.severity === "Medium").length; const missingLow = securityHeaders.filter(h => !h.present && h.severity === "Low").length; // Overall security assessment if (missingHigh > 0) { recommendations.push(`Critical security headers are missing. Add the ${missingHigh} missing high-priority headers first.`); } if (missingMedium > 0) { recommendations.push(`Improve security by adding the ${missingMedium} missing medium-priority headers.`); } if (missingLow > 0) { recommendations.push(`Consider adding the ${missingLow} missing low-priority headers for best practices.`); } // HTTPS enforcement if (!securityHeaders.find(h => h.name === "Strict-Transport-Security")?.present) { recommendations.push("Enforce HTTPS by implementing HSTS (HTTP Strict Transport Security)."); } // XSS protection if (!securityHeaders.find(h => h.name === "Content-Security-Policy")?.present) { recommendations.push("Implement Content-Security-Policy to prevent XSS attacks."); } // General advice recommendations.push("Consider using a security headers scanner like securityheaders.com to regularly audit your site."); return recommendations; } /** * Format security headers results into a readable report */ function formatSecurityHeadersReport( securityHeaders: Array<{ name: string; present: boolean; value: string; description: string; severity: "High" | "Medium" | "Low"; recommendation: string; }>, recommendations: string[], endpoint: string, authInfo: string = '' ): string { let report = `# Security Headers Analysis for ${endpoint}${authInfo}\n\n`; // Overall score const totalHeaders = securityHeaders.length; const presentHeaders = securityHeaders.filter(h => h.present).length; const score = Math.round((presentHeaders / totalHeaders) * 100); report += `## Summary\n\n`; report += `- Security Score: ${score}% (${presentHeaders}/${totalHeaders} headers present)\n`; report += `- Missing Security Headers: ${totalHeaders - presentHeaders}\n\n`; // Headers table report += `## Security Headers\n\n`; // Group by severity for (const severity of ["High", "Medium", "Low"]) { report += `### ${severity} Priority\n\n`; const filteredHeaders = securityHeaders.filter(h => h.severity === severity); for (const header of filteredHeaders) { report += `#### ${header.name}\n`; report += `- Present: ${header.present ? "✅ Yes" : "❌ No"}\n`; if (header.present && header.value) { report += `- Value: \`${header.value}\`\n`; } report += `- Description: ${header.description}\n`; report += `- Recommendation: ${header.recommendation}\n\n`; } } // Recommendations report += `## Overall Recommendations\n\n`; for (const recommendation of recommendations) { report += `- ${recommendation}\n`; } report += `\n## Best Practices\n\n`; report += `1. Regularly audit security headers\n`; report += `2. Keep headers up to date with evolving security standards\n`; report += `3. Test headers in all environments (development, staging, production)\n`; report += `4. Use appropriate security headers based on your application's needs\n`; report += `5. Balance security with functionality - overly restrictive headers can break features\n`; return report; }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ricauts/CyberMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server