/
githubmirror
/
Front-End-Checklist
Обзор
Документация
Войти
/
githubmirror
/
Front-End-Checklist
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
packages/validators/src/validate-security.ts
242 строки
7 KB
David Dias
chore: new v2 version
30 май 2026, 00:54
30 май 2026, 00:54
7c05904
Код
Авторство
О чём код?
#!/usr/bin/env tsx /** * Security Validator * * Ensures: * - No hardcoded secrets * - Proper environment variable usage * - No unsafe operations * - SQL injection prevention * - XSS prevention */ import fs from 'node:fs' interface SecurityViolation { file: string line: number message: string severity: 'error' | 'warning' | 'critical' type: string } const SECRET_PATTERNS = [ { pattern: /api[_-]?key\s*[:=]\s*['"][^'"]{20,}/i, type: 'API Key' }, { pattern: /secret[_-]?key\s*[:=]\s*['"][^'"]{20,}/i, type: 'Secret Key' }, { pattern: /password\s*[:=]\s*['"][^'"]+/i, type: 'Password' }, { pattern: /token\s*[:=]\s*['"][^'"]{20,}/i, type: 'Token' }, { pattern: /private[_-]?key\s*[:=]\s*['"][^'"]+/i, type: 'Private Key' }, { pattern: /aws[_-]?access[_-]?key/i, type: 'AWS Key' }, { pattern: /github[_-]?token/i, type: 'GitHub Token' }, { pattern: /stripe[_-]?key/i, type: 'Stripe Key' } ] const UNSAFE_PATTERNS = [ { pattern: /eval\s*\(/, message: 'Avoid using eval()', severity: 'critical' as const }, { pattern: /innerHTML\s*=/, message: 'Use textContent instead of innerHTML', severity: 'warning' as const }, { pattern: /dangerouslySetInnerHTML/, message: 'Avoid dangerouslySetInnerHTML when possible', severity: 'warning' as const }, { pattern: /document\.write/, message: 'Avoid document.write', severity: 'error' as const }, { pattern: /new Function\(/, message: 'Avoid creating functions from strings', severity: 'critical' as const } ] const SQL_INJECTION_PATTERNS = [ { pattern: /query\s*\(\s*['"`].*\$\{/, message: 'Potential SQL injection - use parameterized queries' }, { pattern: /execute\s*\(\s*['"`].*\+/, message: 'Potential SQL injection - avoid string concatenation in queries' } ] /** * Validates security best practices in code files */ class SecurityValidator { private violations: SecurityViolation[] = [] validateFile(filePath: string): void { const content = fs.readFileSync(filePath, 'utf-8') const lines = content.split('\n') lines.forEach((line, index) => { this.checkHardcodedSecrets(filePath, line, index + 1) this.checkUnsafeOperations(filePath, line, index + 1) this.checkSQLInjection(filePath, line, index + 1) this.checkXSSVulnerabilities(filePath, line, index + 1) this.checkEnvironmentVariables(filePath, line, index + 1) }) } private checkHardcodedSecrets(file: string, line: string, lineNumber: number): void { // Skip comments and test files if (line.trim().startsWith('//') || line.trim().startsWith('*')) return if (file.includes('.test.') || file.includes('.spec.')) return for (const { pattern, type } of SECRET_PATTERNS) { if (pattern.test(line)) { // Check if it's using environment variable if (!line.includes('process.env') && !line.includes('import.meta.env')) { this.violations.push({ file, line: lineNumber, message: `Potential hardcoded ${type} detected`, severity: 'critical', type: 'secret' }) } } } } private checkUnsafeOperations(file: string, line: string, lineNumber: number): void { for (const { pattern, message, severity } of UNSAFE_PATTERNS) { if (pattern.test(line)) { this.violations.push({ file, line: lineNumber, message, severity, type: 'unsafe' }) } } } private checkSQLInjection(file: string, line: string, lineNumber: number): void { for (const { pattern, message } of SQL_INJECTION_PATTERNS) { if (pattern.test(line)) { this.violations.push({ file, line: lineNumber, message, severity: 'critical', type: 'sql-injection' }) } } } private checkXSSVulnerabilities(file: string, line: string, lineNumber: number): void { // Check for unescaped user input if (line.includes('req.query') || line.includes('req.params') || line.includes('req.body')) { if (line.includes('innerHTML') || line.includes('document.write')) { this.violations.push({ file, line: lineNumber, message: 'Potential XSS - user input used in unsafe context', severity: 'critical', type: 'xss' }) } } // Check for missing input validation if (line.includes('parseInt') && !line.includes('Number.isNaN')) { this.violations.push({ file, line: lineNumber, message: 'Validate parseInt results with Number.isNaN', severity: 'warning', type: 'validation' }) } } private checkEnvironmentVariables(file: string, line: string, lineNumber: number): void { // Check for direct process.env access without validation const envPattern = /process\.env\.(\w+)/g const matches = line.matchAll(envPattern) for (const match of matches) { const envVar = match[1] // Check if it's validated if (!line.includes('||') && !line.includes('??') && !line.includes('if')) { this.violations.push({ file, line: lineNumber, message: `Environment variable ${envVar} used without fallback`, severity: 'warning', type: 'env' }) } } } report(): boolean { if (this.violations.length === 0) { // No security issues found return true } const critical = this.violations.filter(v => v.severity === 'critical') const errors = this.violations.filter(v => v.severity === 'error') const warnings = this.violations.filter(v => v.severity === 'warning') if (critical.length > 0) { // Found CRITICAL security issues critical.forEach(_v => { // Critical issue details logged internally }) } if (errors.length > 0) { // Found security errors errors.forEach(_v => { // Error details logged internally }) } if (warnings.length > 0) { // Found security warnings warnings.forEach(_v => { // Warning details logged internally }) } return critical.length === 0 && errors.length === 0 } } /** * Validate security practices in multiple files * @param files - Array of file paths to validate * @returns True if no critical security issues found */ export function validateSecurity(files: string[]): boolean { const validator = new SecurityValidator() for (const file of files) { if (!file.match(/\.(ts|tsx|js|jsx)$/)) continue if (file.includes('node_modules')) continue try { validator.validateFile(file) } catch (_error) { // Error processing file } } return validator.report() } // CLI entry point if (require.main === module) { const args = process.argv.slice(2) const success = validateSecurity(args) process.exit(success ? 0 : 1) }