Skip to main content
Glama

CodeCompass MCP

security.ts12.5 kB
import { SecurityCheck, SecurityIssue } from '../types/index.js'; export class SecurityService { static checkCode(code: string, language: string): SecurityCheck { const issues: SecurityIssue[] = []; // Common security patterns across languages const commonChecks = [ this.checkHardcodedSecrets(code), this.checkSqlInjection(code), this.checkXssVulnerabilities(code), this.checkCommandInjection(code), this.checkInsecureRandomness(code), ]; // Language-specific checks switch (language.toLowerCase()) { case 'javascript': case 'typescript': commonChecks.push( this.checkEvalUsage(code), this.checkInnerHtml(code), this.checkUnsafeRegex(code) ); break; case 'python': commonChecks.push( this.checkPythonEval(code), this.checkPickleUsage(code), this.checkShellCommand(code) ); break; case 'java': commonChecks.push( this.checkJavaDeserialization(code), this.checkRuntimeExec(code) ); break; } // Flatten and filter issues const allIssues = commonChecks.flat().filter(Boolean) as SecurityIssue[]; return { passed: allIssues.length === 0, issues: allIssues, recommendations: this.generateRecommendations(allIssues), }; } static sanitizeCode(code: string): string { // Remove or mask sensitive information let sanitized = code; // Remove API keys and tokens sanitized = sanitized.replace(/['"](sk-[a-zA-Z0-9]{32,})['"]/g, '"<API_KEY_MASKED>"'); sanitized = sanitized.replace(/['"](ghp_[a-zA-Z0-9]{36})['"]/g, '"<GITHUB_TOKEN_MASKED>"'); sanitized = sanitized.replace(/['"](xoxb-[a-zA-Z0-9-]{51,})['"]/g, '"<SLACK_TOKEN_MASKED>"'); // Remove database connection strings sanitized = sanitized.replace(/['"](postgresql:\/\/[^'"]+)['"]/g, '"<DATABASE_URL_MASKED>"'); sanitized = sanitized.replace(/['"](mysql:\/\/[^'"]+)['"]/g, '"<DATABASE_URL_MASKED>"'); sanitized = sanitized.replace(/['"](mongodb:\/\/[^'"]+)['"]/g, '"<DATABASE_URL_MASKED>"'); // Remove email addresses sanitized = sanitized.replace(/['"]([\w\.-]+@[\w\.-]+\.\w+)['"]/g, '"<EMAIL_MASKED>"'); // Remove potential passwords sanitized = sanitized.replace(/password\s*[:=]\s*['"](.*?)['"]/gi, 'password: "<PASSWORD_MASKED>"'); sanitized = sanitized.replace(/secret\s*[:=]\s*['"](.*?)['"]/gi, 'secret: "<SECRET_MASKED>"'); return sanitized; } static isPathSafe(path: string): boolean { // Check for directory traversal if (path.includes('..')) return false; // Check for absolute paths if (path.startsWith('/')) return false; // Check for dangerous characters if (/[<>:"|?*]/.test(path)) return false; // Check for null bytes if (path.includes('\0')) return false; return true; } static validateApiAccess(url: string): boolean { // Only allow GitHub API access return url.startsWith('https://api.github.com/') || url.startsWith('https://github.com/'); } static rateLimit(key: string, limit: number = 100, window: number = 60000): boolean { // Simple in-memory rate limiting const now = Date.now(); const windowStart = now - window; if (!this.rateLimitStore) { this.rateLimitStore = new Map(); } const requests = this.rateLimitStore.get(key) || []; const validRequests = requests.filter((time: number) => time > windowStart); if (validRequests.length >= limit) { return false; } validRequests.push(now); this.rateLimitStore.set(key, validRequests); return true; } private static rateLimitStore: Map<string, number[]>; private static checkHardcodedSecrets(code: string): SecurityIssue[] { const issues: SecurityIssue[] = []; const patterns = [ { pattern: /['"](sk-[a-zA-Z0-9]{32,})['"]/, name: 'OpenAI API Key' }, { pattern: /['"](ghp_[a-zA-Z0-9]{36})['"]/, name: 'GitHub Personal Access Token' }, { pattern: /['"](xoxb-[a-zA-Z0-9-]{51,})['"]/, name: 'Slack Bot Token' }, { pattern: /['"](AIza[0-9A-Za-z-_]{35})['"]/, name: 'Google API Key' }, { pattern: /['"](AKIA[0-9A-Z]{16})['"]/, name: 'AWS Access Key' }, { pattern: /['"](ya29\.[0-9A-Za-z\-_]+)['"]/, name: 'Google OAuth Token' }, ]; for (const { pattern, name } of patterns) { const matches = code.match(pattern); if (matches) { issues.push({ type: 'high', description: `Hardcoded ${name} found in code`, file: 'current', suggestion: `Store ${name} in environment variables or secure configuration`, }); } } return issues; } private static checkSqlInjection(code: string): SecurityIssue[] { const issues: SecurityIssue[] = []; const patterns = [ /query\s*\(\s*['"]\s*SELECT\s.*?\+.*?['"]\s*\)/i, /execute\s*\(\s*['"]\s*SELECT\s.*?\+.*?['"]\s*\)/i, /sql\s*=\s*['"]\s*SELECT\s.*?\+.*?['"]/i, ]; for (const pattern of patterns) { if (pattern.test(code)) { issues.push({ type: 'high', description: 'Potential SQL injection vulnerability', file: 'current', suggestion: 'Use parameterized queries or prepared statements', }); } } return issues; } private static checkXssVulnerabilities(code: string): SecurityIssue[] { const issues: SecurityIssue[] = []; const patterns = [ /dangerouslySetInnerHTML/, /innerHTML\s*=\s*.*?\+/, /document\.write\s*\(/, /eval\s*\(/, ]; for (const pattern of patterns) { if (pattern.test(code)) { issues.push({ type: 'medium', description: 'Potential XSS vulnerability', file: 'current', suggestion: 'Sanitize user input and use safe DOM manipulation methods', }); } } return issues; } private static checkCommandInjection(code: string): SecurityIssue[] { const issues: SecurityIssue[] = []; const patterns = [ /exec\s*\(\s*.*?\+.*?\)/, /system\s*\(\s*.*?\+.*?\)/, /spawn\s*\(\s*.*?\+.*?\)/, /execSync\s*\(\s*.*?\+.*?\)/, ]; for (const pattern of patterns) { if (pattern.test(code)) { issues.push({ type: 'high', description: 'Potential command injection vulnerability', file: 'current', suggestion: 'Validate and sanitize input before passing to system commands', }); } } return issues; } private static checkInsecureRandomness(code: string): SecurityIssue[] { const issues: SecurityIssue[] = []; const patterns = [ /Math\.random\(\)/, /random\.random\(\)/, /rand\(\)/, ]; for (const pattern of patterns) { if (pattern.test(code)) { issues.push({ type: 'medium', description: 'Insecure random number generation', file: 'current', suggestion: 'Use cryptographically secure random number generators', }); } } return issues; } private static checkEvalUsage(code: string): SecurityIssue[] { const issues: SecurityIssue[] = []; if (/eval\s*\(/.test(code)) { issues.push({ type: 'high', description: 'Use of eval() function', file: 'current', suggestion: 'Avoid eval() and use safer alternatives like JSON.parse() or Function constructor', }); } return issues; } private static checkInnerHtml(code: string): SecurityIssue[] { const issues: SecurityIssue[] = []; if (/innerHTML\s*=/.test(code)) { issues.push({ type: 'medium', description: 'Direct use of innerHTML', file: 'current', suggestion: 'Use textContent or sanitize HTML content', }); } return issues; } private static checkUnsafeRegex(code: string): SecurityIssue[] { const issues: SecurityIssue[] = []; // Check for potential ReDoS patterns const redosPatterns = [ /\(\.\*\)\+/, /\(\.\+\)\+/, /\(\.\*\)\*/, /\(\.\+\)\*/, ]; for (const pattern of redosPatterns) { if (pattern.test(code)) { issues.push({ type: 'medium', description: 'Potential ReDoS (Regular Expression Denial of Service) vulnerability', file: 'current', suggestion: 'Review regex patterns for potential catastrophic backtracking', }); } } return issues; } private static checkPythonEval(code: string): SecurityIssue[] { const issues: SecurityIssue[] = []; const patterns = [ /eval\s*\(/, /exec\s*\(/, /compile\s*\(/, ]; for (const pattern of patterns) { if (pattern.test(code)) { issues.push({ type: 'high', description: 'Use of dangerous Python eval/exec functions', file: 'current', suggestion: 'Use safer alternatives like ast.literal_eval() or avoid dynamic code execution', }); } } return issues; } private static checkPickleUsage(code: string): SecurityIssue[] { const issues: SecurityIssue[] = []; if (/pickle\.loads?\s*\(/.test(code)) { issues.push({ type: 'high', description: 'Use of pickle.load() or pickle.loads()', file: 'current', suggestion: 'Avoid pickle for untrusted data, use JSON or other safe serialization formats', }); } return issues; } private static checkShellCommand(code: string): SecurityIssue[] { const issues: SecurityIssue[] = []; const patterns = [ /subprocess\.call\s*\(\s*.*shell\s*=\s*True/, /os\.system\s*\(/, /subprocess\.run\s*\(\s*.*shell\s*=\s*True/, ]; for (const pattern of patterns) { if (pattern.test(code)) { issues.push({ type: 'high', description: 'Use of shell commands with potential injection risk', file: 'current', suggestion: 'Use subprocess without shell=True or validate input thoroughly', }); } } return issues; } private static checkJavaDeserialization(code: string): SecurityIssue[] { const issues: SecurityIssue[] = []; if (/ObjectInputStream|readObject\s*\(/.test(code)) { issues.push({ type: 'high', description: 'Java deserialization vulnerability', file: 'current', suggestion: 'Validate serialized data or use safer serialization methods', }); } return issues; } private static checkRuntimeExec(code: string): SecurityIssue[] { const issues: SecurityIssue[] = []; if (/Runtime\.getRuntime\(\)\.exec\s*\(/.test(code)) { issues.push({ type: 'high', description: 'Use of Runtime.exec() for command execution', file: 'current', suggestion: 'Use ProcessBuilder with proper input validation', }); } return issues; } private static generateRecommendations(issues: SecurityIssue[]): string[] { const recommendations: string[] = []; if (issues.length === 0) { recommendations.push('No security issues detected'); return recommendations; } const highIssues = issues.filter(issue => issue.type === 'high'); const mediumIssues = issues.filter(issue => issue.type === 'medium'); const lowIssues = issues.filter(issue => issue.type === 'low'); if (highIssues.length > 0) { recommendations.push(`Address ${highIssues.length} high-priority security issues immediately`); } if (mediumIssues.length > 0) { recommendations.push(`Review ${mediumIssues.length} medium-priority security issues`); } if (lowIssues.length > 0) { recommendations.push(`Consider addressing ${lowIssues.length} low-priority security issues`); } recommendations.push('Implement security linting in your CI/CD pipeline'); recommendations.push('Regular security audits and dependency updates'); recommendations.push('Use environment variables for sensitive configuration'); return recommendations; } }

Latest Blog Posts

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/TheAlchemist6/codecompass-mcp'

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