xploitscan 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +632 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/commands/scan.ts","../src/utils/files.ts","../src/utils/config.ts","../src/scanners/custom-rules.ts","../src/scanners/semgrep.ts","../src/scanners/gitleaks.ts","../src/scanners/ai-analyzer.ts","../src/scanners/ast-analyzer.ts","../src/scanners/dependency-scanner.ts","../src/scanners/entropy-scanner.ts","../src/scanners/config-analyzer.ts","../src/scanners/multi-file-analyzer.ts","../src/reporters/terminal.ts","../src/reporters/json.ts","../src/reporters/sarif.ts","../src/commands/auth.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { scanCommand } from \"./commands/scan.js\";\nimport { loginCommand, logoutCommand, whoamiCommand } from \"./commands/auth.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"xploitscan\")\n .description(\n \"AI security scanner for vibe-coded apps. Find vulnerabilities before attackers do.\",\n )\n .version(\"0.3.0\");\n\nprogram\n .command(\"scan\")\n .description(\"Scan a directory for security vulnerabilities\")\n .argument(\"[directory]\", \"Directory to scan\", \".\")\n .option(\"--no-ai\", \"Skip AI-powered analysis\")\n .option(\"-f, --format <format>\", \"Output format: terminal, json, sarif\", \"terminal\")\n .option(\"-v, --verbose\", \"Show detailed output\", false)\n .option(\"--diff [base]\", \"Scan only files changed vs base branch (default: main)\")\n .option(\"-w, --watch\", \"Watch for file changes and re-scan automatically\", false)\n .action(async (directory: string, opts: { ai: boolean; format: string; verbose: boolean; diff?: string | boolean; watch: boolean }) => {\n await scanCommand(directory, {\n directory,\n aiAnalysis: opts.ai,\n format: opts.format as \"terminal\" | \"json\" | \"sarif\",\n verbose: opts.verbose,\n diff: opts.diff,\n watch: opts.watch,\n });\n });\n\n// Auth commands\nconst auth = program\n .command(\"auth\")\n .description(\"Manage authentication\");\n\nauth\n .command(\"login\")\n .description(\"Log in to your XploitScan account\")\n .action(loginCommand);\n\nauth\n .command(\"logout\")\n .description(\"Log out of your XploitScan account\")\n .action(logoutCommand);\n\nauth\n .command(\"whoami\")\n .description(\"Show current logged-in user\")\n .action(whoamiCommand);\n\n// Upgrade command (shortcut)\nprogram\n .command(\"upgrade\")\n .description(\"Upgrade to XploitScan Pro for unlimited scans\")\n .action(async () => {\n const { getStoredToken, getCheckoutUrl } = await import(\"./utils/api.js\");\n const chalk = (await import(\"chalk\")).default;\n\n const token = getStoredToken();\n if (!token) {\n console.log(chalk.yellow(\"Please log in first: xploitscan auth login\"));\n return;\n }\n\n console.log(chalk.cyan(\"Creating checkout session...\"));\n const url = await getCheckoutUrl();\n if (url) {\n console.log(chalk.green(`\\nOpen this URL to upgrade:`));\n console.log(chalk.bold.underline(url));\n const { execFile } = require(\"node:child_process\");\n const openCmd = process.platform === \"darwin\" ? \"open\" : process.platform === \"win32\" ? \"start\" : \"xdg-open\";\n execFile(openCmd, [url], () => {});\n } else {\n console.log(chalk.red(\"Failed to create checkout session. Please try again.\"));\n }\n });\n\nprogram.parse();\n","import { resolve, join, relative } from \"node:path\";\nimport { watch as fsWatch } from \"node:fs\";\nimport ora from \"ora\";\nimport chalk from \"chalk\";\nimport type { Finding, ScanOptions, ScanResult } from \"../types.js\";\nimport { collectFiles, readFileContents } from \"../utils/files.js\";\nimport { loadConfig } from \"../utils/config.js\";\nimport { runCustomRules } from \"../scanners/custom-rules.js\";\nimport { runSemgrep } from \"../scanners/semgrep.js\";\nimport { runGitleaks } from \"../scanners/gitleaks.js\";\nimport { analyzeWithAI } from \"../scanners/ai-analyzer.js\";\nimport { buildASTContext } from \"../scanners/ast-analyzer.js\";\nimport { scanDependencies } from \"../scanners/dependency-scanner.js\";\nimport { scanEntropy } from \"../scanners/entropy-scanner.js\";\nimport { scanConfigs } from \"../scanners/config-analyzer.js\";\nimport { scanMultiFile } from \"../scanners/multi-file-analyzer.js\";\nimport { renderTerminalReport } from \"../reporters/terminal.js\";\nimport { renderJsonReport } from \"../reporters/json.js\";\nimport { renderSarifReport } from \"../reporters/sarif.js\";\nimport { checkUsage, incrementUsage, uploadScanResults, isAuthenticated } from \"../utils/api.js\";\n\nexport async function scanCommand(\n directory: string,\n options: Partial<ScanOptions>,\n): Promise<void> {\n const dir = resolve(directory || \".\");\n const format = options.format ?? \"terminal\";\n const verbose = options.verbose ?? false;\n const startTime = Date.now();\n\n // Load config\n const config = await loadConfig(dir);\n const useAI = (options.aiAnalysis ?? config.ai ?? true) && !!process.env.ANTHROPIC_API_KEY;\n\n const isSilent = format !== \"terminal\";\n\n // Step 0: Check usage limits (if authenticated)\n if (isAuthenticated()) {\n const usage = await checkUsage();\n if (!usage.allowed) {\n console.log(chalk.red(\"\\nDaily scan limit reached (3/3 scans used).\"));\n console.log(chalk.yellow(\"Upgrade to Pro for unlimited scans: \") + chalk.bold(\"xploitscan upgrade\"));\n console.log(chalk.gray(`Resets tomorrow. Plan: ${usage.plan}\\n`));\n process.exitCode = 1;\n return;\n }\n if (usage.plan === \"free\" && usage.remaining > 0 && usage.remaining <= 2 && !isSilent) {\n console.log(chalk.gray(` ${usage.remaining} free scan${usage.remaining === 1 ? \"\" : \"s\"} remaining today\\n`));\n }\n }\n\n // Step 1: Collect files\n const spinner = ora({\n text: \"Scanning files...\",\n color: \"cyan\",\n isSilent,\n }).start();\n\n let files: string[];\n try {\n files = await collectFiles(dir);\n } catch (error) {\n spinner.fail(\"Failed to scan directory\");\n console.error(chalk.red(`Error: ${error instanceof Error ? error.message : error}`));\n process.exit(1);\n }\n\n // Diff mode: filter to only changed files\n if (options.diff) {\n const base = typeof options.diff === \"string\" ? options.diff : \"main\";\n try {\n const { execSync } = await import(\"node:child_process\");\n const changedFiles = execSync(`git diff --name-only ${base}`, { cwd: dir, encoding: \"utf-8\" })\n .trim().split(\"\\n\").filter(Boolean);\n files = files.filter(f => changedFiles.some(cf => f.endsWith(cf) || cf.endsWith(f)));\n if (!isSilent) {\n spinner.info(chalk.gray(` Diff mode: scanning ${files.length} changed files vs ${base}`));\n }\n } catch {\n spinner.warn(\"Could not run git diff — scanning all files\");\n }\n }\n\n if (files.length === 0) {\n spinner.warn(\"No source files found in this directory\");\n return;\n }\n\n spinner.text = `Found ${files.length} files. Running security rules...`;\n\n // Step 2: Run all static scanners in parallel\n const allFindings: Finding[] = [];\n\n // 2a: Custom rules with AST context (always runs, instant)\n const fileContentsForAnalysis: { path: string; content: string }[] = [];\n for (const filePath of files) {\n const content = readFileContents(dir, filePath);\n if (!content) continue;\n fileContentsForAnalysis.push({ path: filePath, content });\n\n // Build AST context for false positive reduction\n const astCtx = buildASTContext(content, filePath);\n\n // Skip scanner files scanning themselves\n if (astCtx.isScannerFile) continue;\n\n // Run custom rules with AST-stripped content for comment-heavy files\n const findings = runCustomRules(content, filePath, config.disableRules);\n\n // Add confidence scores based on AST context\n for (const f of findings) {\n if (astCtx.isTestFile) {\n f.confidence = \"low\";\n } else if (astCtx.isConfigFile) {\n f.confidence = \"medium\";\n } else {\n f.confidence = \"high\";\n }\n }\n\n allFindings.push(...findings);\n }\n\n const customCount = allFindings.length;\n if (verbose && customCount > 0) {\n spinner.info(`Custom rules found ${customCount} issues`);\n }\n\n // 2b: Dependency vulnerability scanning\n spinner.text = \"Scanning dependencies...\";\n const depFindings = scanDependencies(fileContentsForAnalysis);\n for (const f of depFindings) { f.confidence = \"high\"; }\n allFindings.push(...depFindings);\n if (verbose && depFindings.length > 0) {\n spinner.info(`Dependency scanner found ${depFindings.length} issues`);\n }\n\n // 2c: Entropy-based secret detection\n spinner.text = \"Scanning for high-entropy secrets...\";\n const entropyFindings = scanEntropy(fileContentsForAnalysis);\n for (const f of entropyFindings) { f.confidence = \"medium\"; }\n allFindings.push(...entropyFindings);\n if (verbose && entropyFindings.length > 0) {\n spinner.info(`Entropy scanner found ${entropyFindings.length} potential secrets`);\n }\n\n // 2d: Configuration file deep analysis\n spinner.text = \"Analyzing configuration files...\";\n const configFindings = scanConfigs(fileContentsForAnalysis);\n for (const f of configFindings) { f.confidence = \"high\"; }\n allFindings.push(...configFindings);\n if (verbose && configFindings.length > 0) {\n spinner.info(`Config analyzer found ${configFindings.length} issues`);\n }\n\n // 2e: Multi-file cross-reference analysis\n spinner.text = \"Running cross-file analysis...\";\n const multiFileFindings = scanMultiFile(fileContentsForAnalysis);\n for (const f of multiFileFindings) { f.confidence = \"medium\"; }\n allFindings.push(...multiFileFindings);\n if (verbose && multiFileFindings.length > 0) {\n spinner.info(`Multi-file analyzer found ${multiFileFindings.length} issues`);\n }\n\n // 2f: Semgrep + Gitleaks (run in parallel, gracefully skip if not installed)\n spinner.text = \"Running external scanners...\";\n spinner.color = \"yellow\";\n\n // Resolve custom rules directory (shipped with xploitscan)\n const rulesDir = resolve(join(import.meta.dirname, \"../../rules\"));\n const fallbackRulesDir = resolve(join(dir, \"../rules\"));\n\n const [semgrepResult, gitleaksResult] = await Promise.allSettled([\n runSemgrep(dir, rulesDir).catch(() => runSemgrep(dir, fallbackRulesDir)).catch(() => ({ findings: [] as Finding[], available: false })),\n runGitleaks(dir).catch(() => ({ findings: [] as Finding[], available: false })),\n ]);\n\n const semgrep = semgrepResult.status === \"fulfilled\" ? semgrepResult.value : { findings: [], available: false };\n const gitleaks = gitleaksResult.status === \"fulfilled\" ? gitleaksResult.value : { findings: [], available: false };\n\n allFindings.push(...semgrep.findings);\n allFindings.push(...gitleaks.findings);\n\n if (verbose) {\n if (semgrep.available) {\n spinner.info(`Semgrep found ${semgrep.findings.length} issues`);\n } else {\n spinner.info(chalk.gray(\"Semgrep not installed — install with: pip install semgrep\"));\n }\n if (gitleaks.available) {\n spinner.info(`Gitleaks found ${gitleaks.findings.length} issues`);\n } else {\n spinner.info(chalk.gray(\"Gitleaks not installed — install with: brew install gitleaks\"));\n }\n }\n\n // Show install hints for missing tools (non-verbose, terminal only)\n if (!isSilent && !verbose) {\n const missing: string[] = [];\n if (!semgrep.available) missing.push(\"semgrep (pip install semgrep)\");\n if (!gitleaks.available) missing.push(\"gitleaks (brew install gitleaks)\");\n if (missing.length > 0) {\n spinner.info(chalk.gray(`Optional: install ${missing.join(\" and \")} for deeper scanning`));\n }\n }\n\n const staticCount = allFindings.length;\n spinner.text = `Static analysis found ${staticCount} issue${staticCount !== 1 ? \"s\" : \"\"}`;\n\n // Step 3: AI analysis (if enabled)\n if (useAI) {\n spinner.text = \"Running AI analysis...\";\n spinner.color = \"magenta\";\n\n try {\n const priorityFiles = files\n .map((path) => ({\n path,\n content: readFileContents(dir, path) ?? \"\",\n }))\n .filter((f) => f.content.length > 0 && f.content.length < 30_000)\n .filter((f) => {\n const isHighPriority =\n /(?:api|server|route|auth|middleware|webhook|payment|stripe|supabase)/i.test(f.path) ||\n allFindings.some((finding) => finding.file === f.path) ||\n /(?:query|execute|fetch|prisma|drizzle|mongoose)/i.test(f.content);\n return isHighPriority;\n })\n .slice(0, 20);\n\n if (priorityFiles.length > 0) {\n const aiFindings = await analyzeWithAI(priorityFiles, allFindings);\n allFindings.push(...aiFindings);\n\n if (verbose && aiFindings.length > 0) {\n spinner.info(`AI analysis found ${aiFindings.length} additional issues`);\n }\n }\n } catch (error) {\n if (error instanceof Error) {\n spinner.warn(`AI analysis skipped: ${error.message}`);\n }\n }\n } else if (!process.env.ANTHROPIC_API_KEY && !isSilent) {\n spinner.info(\n chalk.gray(\"Tip: Set ANTHROPIC_API_KEY for AI-powered contextual analysis\"),\n );\n }\n\n spinner.stop();\n\n // Step 4: Deduplicate findings (same file + line + similar rule)\n const seen = new Set<string>();\n const dedupedFindings = allFindings.filter((f) => {\n // Normalize: group by file:line and a simplified rule key\n const ruleKey = f.source === \"gitleaks\" ? `secret:${f.file}:${f.line}` : `${f.rule}:${f.file}:${f.line}`;\n if (seen.has(ruleKey)) return false;\n seen.add(ruleKey);\n return true;\n });\n\n // Step 5: Render results\n const result: ScanResult = {\n findings: dedupedFindings,\n filesScanned: files.length,\n duration: Date.now() - startTime,\n timestamp: new Date().toISOString(),\n directory: dir,\n };\n\n switch (format) {\n case \"json\":\n renderJsonReport(result);\n break;\n case \"sarif\":\n renderSarifReport(result);\n break;\n default:\n renderTerminalReport(result, fileContentsForAnalysis);\n break;\n }\n\n // Step 6: Upload results and increment usage (if authenticated)\n if (isAuthenticated()) {\n await Promise.allSettled([\n incrementUsage(),\n uploadScanResults({\n directory: dir,\n filesScanned: files.length,\n findings: dedupedFindings,\n duration: Date.now() - startTime,\n }),\n ]);\n }\n\n // Exit with error code if critical/high findings exist\n const hasCritical = dedupedFindings.some(\n (f) => f.severity === \"critical\" || f.severity === \"high\",\n );\n if (hasCritical) {\n process.exitCode = 1;\n }\n\n // Step 7: Watch mode\n if (options.watch) {\n const watchExclude = new Set([\"node_modules\", \".git\", \"dist\", \"build\", \".next\"]);\n const debounceMs = 500;\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n let isScanning = false;\n\n console.log(chalk.cyan(\"\\nWatching for changes... (press Ctrl+C to stop)\"));\n\n fsWatch(dir, { recursive: true }, (_event, filename) => {\n if (!filename) return;\n\n // Skip excluded directories\n const parts = filename.split(\"/\");\n if (parts.some((p) => watchExclude.has(p))) return;\n\n console.log(chalk.gray(`File changed: ${filename}`));\n\n if (debounceTimer) clearTimeout(debounceTimer);\n\n debounceTimer = setTimeout(async () => {\n if (isScanning) return;\n isScanning = true;\n\n console.log(chalk.cyan(\"\\nRe-scanning...\\n\"));\n try {\n await scanCommand(directory, {\n ...options,\n watch: false, // prevent recursive watch\n });\n } catch (error) {\n console.error(chalk.red(`Re-scan error: ${error instanceof Error ? error.message : error}`));\n } finally {\n isScanning = false;\n console.log(chalk.cyan(\"\\nWatching for changes... (press Ctrl+C to stop)\"));\n }\n }, debounceMs);\n });\n\n // Keep the process alive\n await new Promise(() => {});\n }\n}\n","import fg from \"fast-glob\";\nimport ignore from \"ignore\";\nimport { readFileSync, existsSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\n\nconst SOURCE_EXTENSIONS = [\n \"js\", \"jsx\", \"ts\", \"tsx\", \"mjs\", \"cjs\",\n \"vue\", \"svelte\", \"astro\",\n \"py\", \"rb\", \"go\", \"rs\", \"java\", \"php\",\n \"swift\", \"kt\", \"kts\", \"dart\", \"cs\",\n \"c\", \"cpp\", \"h\",\n \"sh\", \"bash\", \"zsh\",\n \"env\", \"yaml\", \"yml\", \"toml\", \"json\", \"xml\",\n \"html\", \"htm\", \"sql\",\n \"properties\", \"ini\", \"cfg\", \"conf\",\n \"tf\", \"hcl\", \"dockerfile\",\n \"erb\", \"jinja\", \"j2\",\n \"gradle\",\n \"r\", \"lua\", \"pl\", \"pm\", \"ex\", \"exs\",\n \"ipynb\", \"md\",\n \"prisma\", \"plist\", \"pbxproj\", \"entitlements\", \"rules\", \"csv\",\n];\n\nconst SOURCE_FILENAMES = [\n \"Dockerfile\", \"Makefile\", \"Gemfile\", \"Rakefile\",\n \"package.json\", \"Cargo.toml\", \"go.mod\", \"requirements.txt\", \"Pipfile\",\n \"next.config.js\", \"next.config.mjs\", \"next.config.ts\", \"vercel.json\",\n \"firebase.json\", \".firebaserc\", \"firestore.rules\",\n \"app.json\", \"app.config.js\", \"eas.json\",\n \"wrangler.toml\", \"netlify.toml\",\n \"drizzle.config.ts\", \"drizzle.config.js\",\n \"Procfile\", \"Caddyfile\", \"nginx.conf\",\n \"AndroidManifest.xml\",\n];\n\nconst ALWAYS_IGNORE = [\n \"node_modules\",\n \".git\",\n \"dist\",\n \"build\",\n \".next\",\n \".nuxt\",\n \".svelte-kit\",\n \"vendor\",\n \"__pycache__\",\n \".venv\",\n \"venv\",\n \"coverage\",\n \".turbo\",\n \"*.min.js\",\n \"*.min.css\",\n \"*.map\",\n \"package-lock.json\",\n \"pnpm-lock.yaml\",\n \"yarn.lock\",\n];\n\nexport async function collectFiles(directory: string): Promise<string[]> {\n const ig = ignore.default();\n\n // Load .gitignore if present\n const gitignorePath = join(directory, \".gitignore\");\n if (existsSync(gitignorePath)) {\n const gitignoreContent = readFileSync(gitignorePath, \"utf-8\");\n ig.add(gitignoreContent);\n }\n\n // Load .xploitscanignore if present\n const xploitscanIgnorePath = join(directory, \".xploitscanignore\");\n if (existsSync(xploitscanIgnorePath)) {\n const xploitscanIgnoreContent = readFileSync(xploitscanIgnorePath, \"utf-8\");\n ig.add(xploitscanIgnoreContent);\n }\n\n // Always ignore these\n ig.add(ALWAYS_IGNORE);\n\n const patterns = SOURCE_EXTENSIONS.map((ext) => `**/*.${ext}`);\n // Also grab dotfiles like .env, .env.local, etc.\n patterns.push(\"**/.env*\");\n // Also grab files matched by name (Dockerfile, Makefile, etc.)\n for (const name of SOURCE_FILENAMES) {\n patterns.push(`**/${name}`);\n }\n\n const files = await fg(patterns, {\n cwd: directory,\n absolute: false,\n dot: true,\n onlyFiles: true,\n ignore: ALWAYS_IGNORE.map((p) => `**/${p}`),\n });\n\n // Apply .gitignore filtering\n return files.filter((file) => !ig.ignores(file));\n}\n\nexport function readFileContents(\n directory: string,\n filePath: string,\n): string | null {\n try {\n const fullPath = resolve(join(directory, filePath));\n if (!fullPath.startsWith(resolve(directory))) {\n throw new Error(\"Path traversal detected\");\n }\n return readFileSync(fullPath, \"utf-8\");\n } catch {\n return null;\n }\n}\n\nexport function getSnippet(\n content: string,\n line: number,\n contextLines = 2,\n): string {\n const lines = content.split(\"\\n\");\n const start = Math.max(0, line - 1 - contextLines);\n const end = Math.min(lines.length, line + contextLines);\n\n return lines\n .slice(start, end)\n .map((l, i) => {\n const lineNum = start + i + 1;\n const marker = lineNum === line ? \">\" : \" \";\n return `${marker} ${lineNum.toString().padStart(4)} | ${l}`;\n })\n .join(\"\\n\");\n}\n","import { cosmiconfig } from \"cosmiconfig\";\nimport { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport interface XploitScanRcConfig {\n rules?: {\n disable?: string[];\n severityOverride?: Record<string, string>;\n };\n scan?: {\n exclude?: string[];\n maxFileSize?: number;\n extensions?: string[];\n };\n output?: {\n format?: \"terminal\" | \"json\" | \"sarif\";\n verbose?: boolean;\n };\n watch?: {\n debounce?: number;\n exclude?: string[];\n };\n}\n\nexport interface XploitScanConfig {\n /** Glob patterns to exclude from scanning */\n exclude?: string[];\n /** Enable/disable AI analysis (requires ANTHROPIC_API_KEY) */\n ai?: boolean;\n /** Severity threshold to report: only show findings at or above this level */\n severity?: \"critical\" | \"high\" | \"medium\" | \"low\" | \"info\";\n /** Custom rules to disable by ID */\n disableRules?: string[];\n /** Severity overrides by rule ID */\n severityOverride?: Record<string, string>;\n /** Max file size in bytes */\n maxFileSize?: number;\n /** Additional file extensions to scan */\n extensions?: string[];\n /** Output format */\n format?: \"terminal\" | \"json\" | \"sarif\";\n /** Verbose output */\n verbose?: boolean;\n /** Watch mode config */\n watch?: {\n debounce?: number;\n exclude?: string[];\n };\n}\n\nconst defaults: XploitScanConfig = {\n exclude: [],\n ai: true,\n severity: \"low\",\n disableRules: [],\n};\n\nfunction loadXploitscanRc(directory: string): XploitScanRcConfig | null {\n try {\n const rcPath = join(directory, \".xploitscanrc\");\n const content = readFileSync(rcPath, \"utf-8\");\n return JSON.parse(content) as XploitScanRcConfig;\n } catch {\n return null;\n }\n}\n\nfunction mergeRcIntoConfig(\n base: XploitScanConfig,\n rc: XploitScanRcConfig,\n): XploitScanConfig {\n const merged = { ...base };\n\n // Merge rules\n if (rc.rules) {\n if (rc.rules.disable) {\n merged.disableRules = [\n ...new Set([...(merged.disableRules ?? []), ...rc.rules.disable]),\n ];\n }\n if (rc.rules.severityOverride) {\n merged.severityOverride = {\n ...(merged.severityOverride ?? {}),\n ...rc.rules.severityOverride,\n };\n }\n }\n\n // Merge scan settings\n if (rc.scan) {\n if (rc.scan.exclude) {\n merged.exclude = [\n ...new Set([...(merged.exclude ?? []), ...rc.scan.exclude]),\n ];\n }\n if (rc.scan.maxFileSize !== undefined) {\n merged.maxFileSize = rc.scan.maxFileSize;\n }\n if (rc.scan.extensions) {\n merged.extensions = [\n ...new Set([...(merged.extensions ?? []), ...rc.scan.extensions]),\n ];\n }\n }\n\n // Merge output settings (rc takes priority)\n if (rc.output) {\n if (rc.output.format !== undefined) {\n merged.format = rc.output.format;\n }\n if (rc.output.verbose !== undefined) {\n merged.verbose = rc.output.verbose;\n }\n }\n\n // Merge watch settings\n if (rc.watch) {\n merged.watch = {\n ...(merged.watch ?? {}),\n ...rc.watch,\n };\n }\n\n return merged;\n}\n\nexport async function loadConfig(\n directory: string,\n): Promise<XploitScanConfig> {\n const explorer = cosmiconfig(\"xploitscan\");\n\n let config = { ...defaults };\n\n try {\n const result = await explorer.search(directory);\n if (result && result.config) {\n config = { ...defaults, ...result.config };\n }\n } catch {\n // Config loading failed, use defaults\n }\n\n // Load .xploitscanrc and merge (rc takes priority)\n const rc = loadXploitscanRc(directory);\n if (rc) {\n config = mergeRcIntoConfig(config, rc);\n }\n\n return config;\n}\n","import type { CustomRule, Finding, RuleMatch } from \"../types.js\";\nimport { readFileContents, getSnippet } from \"../utils/files.js\";\n\n// ────────────────────────────────────────────\n// GLOBAL PRE-FILTERS\n// Reduces false positives before any rule runs\n// ────────────────────────────────────────────\n\n// Broad test/mock/fixture file detection\nconst TEST_FILE_PATTERN = /(?:\\.test\\.|\\.spec\\.|__tests__|__mocks__|\\.stories\\.|\\.story\\.|\\/test\\/|\\/tests\\/|\\/fixtures?\\/|\\/mocks?\\/|\\.mock\\.|test-utils|testing|\\.cy\\.|\\.e2e\\.)/i;\n\nfunction isTestFile(filePath: string): boolean {\n return TEST_FILE_PATTERN.test(filePath);\n}\n\n// Check if a match falls on a comment line (JS/TS/Python/Ruby/YAML/HTML)\nfunction isCommentLine(content: string, matchIndex: number): boolean {\n const lineStart = content.lastIndexOf(\"\\n\", matchIndex - 1) + 1;\n const lineText = content.substring(lineStart, content.indexOf(\"\\n\", matchIndex)).trimStart();\n return (\n lineText.startsWith(\"//\") ||\n lineText.startsWith(\"#\") ||\n lineText.startsWith(\"*\") ||\n lineText.startsWith(\"/*\") ||\n lineText.startsWith(\"<!--\") ||\n lineText.startsWith(\"'\") && lineText.length > 1 && /\\.(vb|bas)$/i.test(\"\") // VB comments\n );\n}\n\n// Check if a match is inside a string literal that's a fix/description message\n// (e.g., inside a findMatches callback or rule description)\nfunction isInsideFixMessage(content: string, matchIndex: number): boolean {\n const lineStart = content.lastIndexOf(\"\\n\", matchIndex - 1) + 1;\n const lineText = content.substring(lineStart, content.indexOf(\"\\n\", matchIndex));\n // Skip if the line looks like a fix suggestion string or rule description\n return /(?:fix|description|message|suggestion|hint|help|example|doc|comment)\\s*[:=(]/i.test(lineText) ||\n /return\\s*[\"'`].*(?:Use|Replace|Add|Move|Set|Enable|Disable|Never|Don't|Do not|Instead)/i.test(lineText);\n}\n\n// Context-aware matching: checks if mitigation exists within N lines after the match\nfunction hasMitigationNearby(content: string, matchIndex: number, mitigationPattern: RegExp, linesAhead: number = 5): boolean {\n const lines = content.split(\"\\n\");\n const matchLine = content.substring(0, matchIndex).split(\"\\n\").length - 1;\n const endLine = Math.min(matchLine + linesAhead, lines.length - 1);\n const nearbyContent = lines.slice(matchLine, endLine + 1).join(\"\\n\");\n return mitigationPattern.test(nearbyContent);\n}\n\n// Helper to find all regex matches with line numbers\n// Automatically skips matches on comment lines and fix messages\nfunction findMatches(\n content: string,\n pattern: RegExp,\n rule: Omit<CustomRule, \"check\">,\n filePath: string,\n fixTemplate?: (match: RegExpExecArray) => string,\n): RuleMatch[] {\n const matches: RuleMatch[] = [];\n const lines = content.split(\"\\n\");\n let m: RegExpExecArray | null;\n const re = new RegExp(pattern.source, pattern.flags.includes(\"g\") ? pattern.flags : `${pattern.flags}g`);\n\n while ((m = re.exec(content)) !== null) {\n // Skip matches on comment lines\n if (isCommentLine(content, m.index)) continue;\n // Skip matches inside fix/description strings\n if (isInsideFixMessage(content, m.index)) continue;\n\n const lineNum = content.substring(0, m.index).split(\"\\n\").length;\n matches.push({\n rule: rule.id,\n title: rule.title,\n severity: rule.severity,\n category: rule.category,\n file: filePath,\n line: lineNum,\n snippet: getSnippet(content, lineNum),\n fix: fixTemplate?.(m),\n });\n }\n\n return matches;\n}\n\n// ────────────────────────────────────────────\n// RULE DEFINITIONS\n// ────────────────────────────────────────────\n\nconst hardcodedSecrets: CustomRule = {\n id: \"VC001\",\n title: \"Hardcoded API Key or Secret\",\n severity: \"critical\",\n category: \"Secrets\",\n description: \"API keys, tokens, or secrets hardcoded in source code can be extracted by anyone with access to the code.\",\n check(content, filePath) {\n // Skip .env.example, template, test, and documentation files\n if (filePath.endsWith(\".example\") || filePath.endsWith(\".template\")) return [];\n if (isTestFile(filePath)) return [];\n if (filePath.match(/\\.(md|txt|rst|adoc)$/)) return [];\n\n const patterns = [\n // Generic API key patterns — require actual value assignment, not variable declarations\n /(?:api[_-]?key|apikey|api[_-]?secret)\\s*[:=]\\s*[\"'`]([a-zA-Z0-9_\\-]{20,})[\"'`]/gi,\n // AWS keys\n /(?:AKIA|ABIA|ACCA|ASIA)[A-Z0-9]{16}/g,\n // Stripe keys\n /(?:sk_live|pk_live|sk_test|pk_test)_[a-zA-Z0-9]{20,}/g,\n // Supabase anon/service keys (JWT format)\n /(?:supabase[_-]?(?:anon|service)[_-]?key|SUPABASE_(?:ANON|SERVICE_ROLE)_KEY)\\s*[:=]\\s*[\"'`](eyJ[a-zA-Z0-9_-]{50,})[\"'`]/gi,\n // OpenAI keys\n /sk-[a-zA-Z0-9]{20,}T3BlbkFJ[a-zA-Z0-9]{20,}/g,\n // Generic tokens in assignments — require standalone word and longer min length\n /(?:^|[\\s,({])(?:token|secret|password|passwd|pwd)\\s*[:=]\\s*[\"'`]([a-zA-Z0-9_\\-!@#$%^&*]{20,})[\"'`]/gim,\n // Private keys\n /-----BEGIN (?:RSA |EC |DSA )?PRIVATE KEY-----/g,\n // Database URLs with credentials\n /(?:postgres|mysql|mongodb(?:\\+srv)?):\\/\\/[^:]+:[^@]+@[^/\\s\"'`]+/gi,\n ];\n\n const matches: RuleMatch[] = [];\n for (const pattern of patterns) {\n matches.push(\n ...findMatches(content, pattern, hardcodedSecrets, filePath, () =>\n \"Move this secret to an environment variable and add it to .env (not committed to git). Use .env.example to document the required variables.\"\n ),\n );\n }\n return matches;\n },\n};\n\nconst exposedEnvFile: CustomRule = {\n id: \"VC002\",\n title: \"Environment File May Be Committed\",\n severity: \"high\",\n category: \"Secrets\",\n description: \".env files containing secrets may be committed to version control.\",\n check(content, filePath) {\n // Only applies to .env files (not .env.example)\n if (!filePath.match(/\\.env(?:\\.[a-z]+)?$/) || filePath.includes(\"example\")) return [];\n\n const hasSecrets = /(?:KEY|SECRET|TOKEN|PASSWORD|PRIVATE|DATABASE_URL)\\s*=/i.test(content);\n if (!hasSecrets) return [];\n\n return [{\n rule: \"VC002\",\n title: exposedEnvFile.title,\n severity: \"high\",\n category: \"Secrets\",\n file: filePath,\n line: 1,\n snippet: getSnippet(content, 1),\n fix: 'Add \".env*\" to your .gitignore file and remove this file from git history with: git rm --cached ' + filePath,\n }];\n },\n};\n\nconst missingAuthMiddleware: CustomRule = {\n id: \"VC003\",\n title: \"API Route Missing Authentication\",\n severity: \"high\",\n category: \"Authentication\",\n description: \"API routes without authentication checks allow unauthorized access.\",\n check(content, filePath) {\n // Only check API route files\n const isApiRoute = /(?:\\/api\\/|routes?\\/|controllers?\\/|endpoints?\\/)/.test(filePath) ||\n filePath.includes(\"server.\");\n if (!isApiRoute) return [];\n\n // Look for route handlers without auth checks\n const routePatterns = [\n // Express/Hono style\n /\\.(get|post|put|patch|delete)\\s*\\(\\s*[\"'`][^\"'`]+[\"'`]\\s*,\\s*(?:async\\s+)?\\(?(?:req|c|ctx)/gi,\n // Next.js API routes\n /export\\s+(?:async\\s+)?function\\s+(?:GET|POST|PUT|PATCH|DELETE)\\s*\\(/gi,\n ];\n\n // Skip test files\n if (filePath.includes(\"test\") || filePath.includes(\"spec\") || filePath.includes(\"mock\")) return [];\n\n const authPatterns = [\n /auth/i, /session/i, /jwt/i, /bearer/i, /middleware/i,\n /getUser/i, /currentUser/i, /isAuthenticated/i, /requireAuth/i,\n /clerk/i, /supabase\\.auth/i, /getServerSession/i, /getToken/i,\n /protect/i, /guard/i, /verifyToken/i, /validateToken/i, /withAuth/i,\n /passport/i, /firebase\\.auth/i, /cognito/i,\n ];\n\n const hasAuth = authPatterns.some((p) => p.test(content));\n if (hasAuth) return [];\n\n const matches: RuleMatch[] = [];\n for (const pattern of routePatterns) {\n matches.push(\n ...findMatches(content, pattern, missingAuthMiddleware, filePath, () =>\n \"Add authentication middleware to protect this route. Check the user's session/token before processing the request.\"\n ),\n );\n }\n return matches;\n },\n};\n\nconst supabaseNoRLS: CustomRule = {\n id: \"VC004\",\n title: \"Supabase Client Without Row Level Security\",\n severity: \"critical\",\n category: \"Authorization\",\n description: \"Using Supabase with the service role key or bypassing RLS exposes all database rows to any user.\",\n check(content, filePath) {\n const matches: RuleMatch[] = [];\n\n // Service role key used in client-side code\n if (\n /supabase_service_role|service_role_key/i.test(content) &&\n (/[\"']use client[\"']/.test(content) || filePath.match(/\\.(jsx|tsx|vue|svelte)$/))\n ) {\n matches.push(\n ...findMatches(\n content,\n /service_role/gi,\n supabaseNoRLS,\n filePath,\n () => \"Never expose the service_role key in client-side code. Use the anon key with RLS policies instead.\",\n ),\n );\n }\n\n // .rpc() or direct table access without .auth\n if (/createClient/i.test(content) && /\\.from\\(/.test(content)) {\n const hasRLSBypass = /\\.rpc\\(|auth\\.admin|service_role/i.test(content);\n if (hasRLSBypass) {\n matches.push(\n ...findMatches(\n content,\n /\\.rpc\\(|auth\\.admin/gi,\n { ...supabaseNoRLS, title: \"Supabase RLS Bypass Detected\" },\n filePath,\n () => \"Ensure RLS policies are enabled on all tables and avoid bypassing them with service_role or admin methods in user-facing code.\",\n ),\n );\n }\n }\n\n return matches;\n },\n};\n\nconst stripeWebhookUnprotected: CustomRule = {\n id: \"VC005\",\n title: \"Unprotected Stripe Webhook Endpoint\",\n severity: \"critical\",\n category: \"Payment Security\",\n description: \"Stripe webhook endpoints without signature verification allow attackers to fake payment events.\",\n check(content, filePath) {\n // Only check files that reference Stripe webhooks\n if (!/stripe|webhook/i.test(content)) return [];\n\n const hasWebhookRoute = /webhook/i.test(filePath) ||\n /(?:post|handler).*webhook/i.test(content);\n if (!hasWebhookRoute) return [];\n\n // Check for signature verification\n const hasVerification = /constructEvent|verifyHeader|stripe-signature|webhook_secret/i.test(content);\n if (hasVerification) return [];\n\n return findMatches(\n content,\n /webhook/gi,\n stripeWebhookUnprotected,\n filePath,\n () =>\n \"Verify the Stripe webhook signature using stripe.webhooks.constructEvent(body, sig, webhookSecret) to prevent forged payment events.\",\n );\n },\n};\n\nconst sqlInjection: CustomRule = {\n id: \"VC006\",\n title: \"Potential SQL Injection\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"String concatenation or template literals in SQL queries allow attackers to execute arbitrary database commands.\",\n check(content, filePath) {\n const patterns = [\n // Template literals in SQL\n /(?:query|execute|raw|sql)\\s*\\(\\s*`[^`]*\\$\\{/gi,\n // String concatenation in SQL\n /(?:query|execute)\\s*\\(\\s*[\"'][^\"']*[\"']\\s*\\+/gi,\n // Direct variable interpolation\n /(?:SELECT|INSERT|UPDATE|DELETE|WHERE)\\s+.*\\$\\{(?!.*parameterized)/gi,\n ];\n\n const matches: RuleMatch[] = [];\n\n // Skip if using parameterized queries / prepared statements\n const usesParams = /\\?\\s*,|\\$\\d+|:[\\w]+|\\bprepare\\b|\\bplaceholder\\b/i.test(content);\n if (usesParams) return [];\n\n for (const pattern of patterns) {\n matches.push(\n ...findMatches(content, pattern, sqlInjection, filePath, () =>\n \"Use parameterized queries or prepared statements instead of string interpolation. Example: db.query('SELECT * FROM users WHERE id = ?', [userId])\"\n ),\n );\n }\n return matches;\n },\n};\n\nconst xssVulnerability: CustomRule = {\n id: \"VC007\",\n title: \"Potential Cross-Site Scripting (XSS)\",\n severity: \"high\",\n category: \"Injection\",\n description: \"Rendering user input without sanitization allows attackers to inject malicious scripts.\",\n check(content, filePath) {\n // Skip if file is a sanitizer utility or already uses DOMPurify\n if (/(?:sanitize|purify|escape|xss)/i.test(filePath)) return [];\n if (/DOMPurify\\.sanitize|sanitizeHtml|xss\\(|escapeHtml/i.test(content)) return [];\n const patterns = [\n // React dangerouslySetInnerHTML\n /dangerouslySetInnerHTML\\s*=\\s*\\{\\s*\\{\\s*__html\\s*:/g,\n // Direct innerHTML assignment\n /\\.innerHTML\\s*=\\s*(?![\"'`]\\s*$)/gm,\n // document.write\n /document\\.write\\s*\\(/g,\n // v-html in Vue\n /v-html\\s*=/g,\n // {@html} in Svelte\n /\\{@html\\s/g,\n ];\n\n const matches: RuleMatch[] = [];\n for (const pattern of patterns) {\n matches.push(\n ...findMatches(content, pattern, xssVulnerability, filePath, () =>\n \"Sanitize user input before rendering as HTML. Use a library like DOMPurify: DOMPurify.sanitize(userInput)\"\n ),\n );\n }\n return matches;\n },\n};\n\nconst noRateLimiting: CustomRule = {\n id: \"VC008\",\n title: \"API Endpoint Without Rate Limiting\",\n severity: \"medium\",\n category: \"Availability\",\n description: \"API endpoints without rate limiting are vulnerable to abuse and denial-of-service attacks.\",\n check(content, filePath) {\n // Only check main server/app entry files\n const isEntryFile = /(?:server|app|index|main)\\.[jt]sx?$/.test(filePath) ||\n filePath.includes(\"middleware\");\n if (!isEntryFile) return [];\n\n // Check if this is a server file\n const isServer = /(?:express|hono|fastify|koa|next|createServer|listen\\()/i.test(content);\n if (!isServer) return [];\n\n // Check for rate limiting\n const hasRateLimit = /rate.?limit|throttle|express-rate-limit|@elysiajs\\/rate-limit|hono.*limiter/i.test(content);\n if (hasRateLimit) return [];\n\n return [{\n rule: \"VC008\",\n title: noRateLimiting.title,\n severity: \"medium\",\n category: \"Availability\",\n file: filePath,\n line: 1,\n snippet: getSnippet(content, 1),\n fix: \"Add rate limiting middleware to your server. For Express: npm install express-rate-limit. For other frameworks, check their rate limiting plugins.\",\n }];\n },\n};\n\nconst corsWildcard: CustomRule = {\n id: \"VC009\",\n title: \"CORS Allows All Origins\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Wildcard CORS (*) allows any website to make requests to your API, potentially exposing user data.\",\n check(content, filePath) {\n if (isTestFile(filePath)) return [];\n const patterns = [\n /cors\\(\\s*\\)/g, // cors() with no options = allow all\n /origin\\s*:\\s*[\"'`]\\*[\"'`]/g,\n /[\"'`]Access-Control-Allow-Origin[\"'`]\\s*,\\s*[\"'`]\\*[\"'`]/g,\n /origin\\s*:\\s*true/g,\n ];\n\n const matches: RuleMatch[] = [];\n for (const pattern of patterns) {\n matches.push(\n ...findMatches(content, pattern, corsWildcard, filePath, () =>\n \"Restrict CORS to your specific frontend domain(s): cors({ origin: 'https://yourdomain.com' })\"\n ),\n );\n }\n return matches;\n },\n};\n\nconst clientSideAuth: CustomRule = {\n id: \"VC010\",\n title: \"Client-Side Only Authorization\",\n severity: \"high\",\n category: \"Authorization\",\n description: \"Hiding UI elements based on roles without server-side checks lets attackers bypass restrictions using DevTools.\",\n check(content, filePath) {\n // Only check frontend component files\n if (!filePath.match(/\\.(jsx|tsx|vue|svelte)$/)) return [];\n\n const matches: RuleMatch[] = [];\n\n // Pattern: conditional rendering based on role/admin without server check\n const rolePatterns = [\n /\\{.*(?:isAdmin|role\\s*===?\\s*[\"'`]admin[\"'`]|user\\.role).*&&/gi,\n /v-if\\s*=\\s*[\"'`].*(?:isAdmin|role\\s*===?\\s*'admin')/gi,\n ];\n\n for (const pattern of rolePatterns) {\n // Only flag if the file has no server-side fetch for auth verification\n const hasServerCheck = /getServerSession|getUser|server|api\\/auth|middleware/i.test(content);\n if (hasServerCheck) continue;\n\n matches.push(\n ...findMatches(content, pattern, clientSideAuth, filePath, () =>\n \"Client-side role checks only hide UI — they don't prevent access. Always verify permissions on the server/API side too.\"\n ),\n );\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC011 – Secret in NEXT_PUBLIC_ env var\n// ────────────────────────────────────────────\n\nconst nextPublicSecret: CustomRule = {\n id: \"VC011\",\n title: \"Secret in NEXT_PUBLIC_ Environment Variable\",\n severity: \"critical\",\n category: \"Secrets\",\n description: \"NEXT_PUBLIC_ variables are exposed to the browser. Secrets placed here are visible to anyone.\",\n check(content, filePath) {\n if (!filePath.match(/\\.env/) && !filePath.match(/next\\.config/)) return [];\n const patterns = [\n /NEXT_PUBLIC_[A-Z_]*(?:SECRET|KEY|TOKEN|PASSWORD|PRIVATE)[A-Z_]*\\s*=\\s*.+/gi,\n /NEXT_PUBLIC_[A-Z_]*(?:SUPABASE_SERVICE|CLERK_SECRET|STRIPE_SECRET)[A-Z_]*\\s*=\\s*.+/gi,\n ];\n const matches: RuleMatch[] = [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, nextPublicSecret, filePath, () =>\n \"Remove the NEXT_PUBLIC_ prefix. Only use NEXT_PUBLIC_ for values safe to expose in the browser.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC012 – Firebase config in client code\n// ────────────────────────────────────────────\n\nconst firebaseClientConfig: CustomRule = {\n id: \"VC012\",\n title: \"Firebase Config with API Key in Client Code\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Firebase config objects in client code expose your API key. While Firebase API keys aren't secret, they should be restricted in the Firebase console.\",\n check(content, filePath) {\n if (!/firebase/i.test(content)) return [];\n const patterns = [\n /firebaseConfig\\s*=\\s*\\{[^}]*apiKey\\s*:/gi,\n /initializeApp\\s*\\(\\s*\\{[^}]*apiKey\\s*:/gi,\n ];\n const matches: RuleMatch[] = [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, firebaseClientConfig, filePath, () =>\n \"Move Firebase config to environment variables. Restrict the API key in Firebase Console > Project Settings > API restrictions.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC013 – Supabase anon key for admin ops\n// ────────────────────────────────────────────\n\nconst supabaseAnonAdmin: CustomRule = {\n id: \"VC013\",\n title: \"Supabase Anon Key Used for Admin Operations\",\n severity: \"high\",\n category: \"Authorization\",\n description: \"Using the Supabase anon key for operations that require elevated privileges is insecure.\",\n check(content, filePath) {\n if (!/supabase/i.test(content)) return [];\n if (!/anon/i.test(content)) return [];\n if (/service_role/i.test(content)) return [];\n const patterns = [\n /supabase[^.]*\\.auth\\.admin/gi,\n /supabase[^.]*\\.rpc\\s*\\(/gi,\n ];\n const matches: RuleMatch[] = [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, supabaseAnonAdmin, filePath, () =>\n \"Use the service_role key on the server side for admin operations. Never expose it to the client.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC014 – .env not in .gitignore\n// ────────────────────────────────────────────\n\nconst envNotGitignored: CustomRule = {\n id: \"VC014\",\n title: \".env File Not in .gitignore\",\n severity: \"high\",\n category: \"Secrets\",\n description: \"If .env is not listed in .gitignore, secrets will be committed to version control.\",\n check(content, filePath) {\n if (!filePath.endsWith(\".gitignore\")) return [];\n if (/\\.env/i.test(content)) return [];\n return [{\n rule: \"VC014\", title: envNotGitignored.title, severity: \"high\" as const, category: \"Secrets\",\n file: filePath, line: 1, snippet: getSnippet(content, 1),\n fix: 'Add \".env*\" to your .gitignore file to prevent committing secrets.',\n }];\n },\n};\n\n// ────────────────────────────────────────────\n// VC015 – eval() / new Function()\n// ────────────────────────────────────────────\n\nconst evalUsage: CustomRule = {\n id: \"VC015\",\n title: \"Use of eval() or Function Constructor\",\n severity: \"high\",\n category: \"Injection\",\n description: \"eval() and new Function() execute arbitrary code, creating severe injection risks. Common in AI-generated code.\",\n check(content, filePath) {\n if (filePath.includes(\"node_modules\") || filePath.includes(\".min.\")) return [];\n if (filePath.match(/(?:webpack|rollup|vite|jest|babel|tsup|esbuild)\\.config/i)) return [];\n if (isTestFile(filePath)) return [];\n // Skip files that are linters/scanners/rule engines (they reference eval in detection patterns)\n if (filePath.match(/(?:rules?|scanner|lint|check|detect|analyz)/i) && /\\.check\\s*\\(|findMatches/i.test(content)) return [];\n const patterns = [\n // Actual eval() calls — not in strings or regex patterns\n /\\beval\\s*\\(\\s*(?)/g,\n /new\\s+Function\\s*\\(\\s*(?![\"'`])/g,\n ];\n // Skip if eval is only in a string (e.g., devtool: 'eval-source-map')\n const hasEvalInString = /[\"'`]eval(?:-source-map|[\"'`])/i.test(content);\n if (hasEvalInString && !/\\beval\\s*\\([^)]*(?:req\\.|body\\.|input|params|user|data)/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n for (const p of patterns) {\n const rawMatches = findMatches(content, p, evalUsage, filePath, () =>\n \"Replace eval() with JSON.parse() for data, or a proper parser for expressions. Never pass user input to eval().\"\n );\n // Skip matches on lines containing devtool or source-map config\n for (const rm of rawMatches) {\n const lineStart = content.lastIndexOf(\"\\n\", content.split(\"\\n\").slice(0, rm.line - 1).join(\"\\n\").length) + 1;\n const lineEnd = content.indexOf(\"\\n\", lineStart + 1);\n const lineText = content.substring(lineStart, lineEnd === -1 ? content.length : lineEnd);\n if (/devtool|source-map/i.test(lineText)) continue;\n matches.push(rm);\n }\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC016 – Unvalidated redirect\n// ────────────────────────────────────────────\n\nconst unvalidatedRedirect: CustomRule = {\n id: \"VC016\",\n title: \"Unvalidated Redirect\",\n severity: \"high\",\n category: \"Injection\",\n description: \"Redirecting users to URLs from untrusted input enables phishing attacks.\",\n check(content, filePath) {\n const patterns = [\n /window\\.location\\s*=\\s*(?![\"'`]https?:\\/\\/)/g,\n /window\\.location\\.href\\s*=\\s*(?![\"'`]https?:\\/\\/)/g,\n /window\\.location\\.assign\\s*\\(\\s*(?![\"'`]https?:\\/\\/)/g,\n /window\\.location\\.replace\\s*\\(\\s*(?![\"'`]https?:\\/\\/)/g,\n /res\\.redirect\\s*\\(\\s*(?:req\\.|params\\.|query\\.)/gi,\n ];\n const matches: RuleMatch[] = [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, unvalidatedRedirect, filePath, () =>\n \"Validate redirect URLs against an allowlist of trusted domains. Never redirect to user-supplied URLs directly.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC017 – Insecure cookie settings\n// ────────────────────────────────────────────\n\nconst insecureCookies: CustomRule = {\n id: \"VC017\",\n title: \"Insecure Cookie Settings\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Cookies without httpOnly, secure, or sameSite flags are vulnerable to theft and CSRF attacks.\",\n check(content, filePath) {\n if (isTestFile(filePath)) return [];\n if (!/cookie/i.test(content)) return [];\n const setCookiePattern = /(?:set-cookie|setCookie|cookie\\s*=|res\\.cookie\\s*\\()/gi;\n if (!setCookiePattern.test(content)) return [];\n const hasHttpOnly = /httpOnly\\s*:\\s*true|httponly/i.test(content);\n const hasSecure = /secure\\s*:\\s*true|;\\s*secure/i.test(content);\n const hasSameSite = /sameSite\\s*:|samesite/i.test(content);\n const matches: RuleMatch[] = [];\n if (!hasHttpOnly || !hasSecure || !hasSameSite) {\n const missing: string[] = [];\n if (!hasHttpOnly) missing.push(\"httpOnly\");\n if (!hasSecure) missing.push(\"secure\");\n if (!hasSameSite) missing.push(\"sameSite\");\n matches.push(...findMatches(content, /(?:set-cookie|setCookie|cookie\\s*=|res\\.cookie\\s*\\()/gi, insecureCookies, filePath, () =>\n `Add missing cookie flags: ${missing.join(\", \")}. Example: { httpOnly: true, secure: true, sameSite: 'lax' }`\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC018 – Exposed auth provider secret key\n// ────────────────────────────────────────────\n\nconst exposedAuthSecret: CustomRule = {\n id: \"VC018\",\n title: \"Exposed Clerk/Auth Secret Key\",\n severity: \"critical\",\n category: \"Secrets\",\n description: \"Auth provider secret keys (Clerk, Auth0, NextAuth) must never be in client-side code or NEXT_PUBLIC_ variables.\",\n check(content, filePath) {\n const isClientFile = filePath.match(/\\.(jsx|tsx|vue|svelte)$/) || /[\"']use client[\"']/.test(content);\n const isEnvFile = filePath.match(/\\.env/);\n if (!isClientFile && !isEnvFile) return [];\n const patterns: RegExp[] = [];\n if (isClientFile) {\n patterns.push(\n /CLERK_SECRET_KEY/g,\n /AUTH0_CLIENT_SECRET/g,\n /NEXTAUTH_SECRET/g,\n );\n }\n if (isEnvFile) {\n patterns.push(\n /NEXT_PUBLIC_CLERK_SECRET/gi,\n /NEXT_PUBLIC_AUTH0_SECRET/gi,\n /NEXT_PUBLIC_NEXTAUTH_SECRET/gi,\n );\n }\n const matches: RuleMatch[] = [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, exposedAuthSecret, filePath, () =>\n \"Move this secret to a server-side environment variable (without the NEXT_PUBLIC_ prefix). Never expose auth secrets to the browser.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC019 – Insecure Electron BrowserWindow\n// ────────────────────────────────────────────\n\nconst insecureElectronWindow: CustomRule = {\n id: \"VC019\",\n title: \"Insecure Electron BrowserWindow Configuration\",\n severity: \"high\",\n category: \"Configuration\",\n description: \"Electron BrowserWindow with nodeIntegration enabled, contextIsolation disabled, or sandbox disabled allows renderer processes to access Node.js APIs, enabling remote code execution.\",\n check(content, filePath) {\n if (isTestFile(filePath)) return [];\n if (!/BrowserWindow/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /nodeIntegration\\s*:\\s*true/g,\n /contextIsolation\\s*:\\s*false/g,\n /sandbox\\s*:\\s*false/g,\n /webSecurity\\s*:\\s*false/g,\n /allowRunningInsecureContent\\s*:\\s*true/g,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, insecureElectronWindow, filePath, (m) =>\n `Set ${m[0].split(\":\")[0].trim()}: ${m[0].includes(\"true\") ? \"false\" : \"true\"}. Enable contextIsolation, sandbox, and webSecurity; disable nodeIntegration and allowRunningInsecureContent.`\n ));\n }\n // Check for BrowserWindow without sandbox/webSecurity set at all\n if (/new\\s+BrowserWindow\\s*\\(/g.test(content)) {\n if (!/sandbox\\s*:/i.test(content)) {\n matches.push(...findMatches(content, /new\\s+BrowserWindow\\s*\\(/g, { ...insecureElectronWindow, title: \"Electron BrowserWindow Missing sandbox:true\" }, filePath, () =>\n \"Add sandbox: true to BrowserWindow webPreferences for defense in depth.\"\n ));\n }\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC020 – Missing Content Security Policy\n// ────────────────────────────────────────────\n\nconst missingCSP: CustomRule = {\n id: \"VC020\",\n title: \"Missing Content Security Policy (CSP)\",\n severity: \"high\",\n category: \"Configuration\",\n description: \"Without a Content-Security-Policy header or meta tag, your app is vulnerable to XSS and data injection attacks.\",\n check(content, filePath) {\n // Check HTML files for missing CSP meta tag\n if (filePath.match(/\\.(html|htm)$/)) {\n if (!/Content-Security-Policy/i.test(content)) {\n return [{\n rule: \"VC020\", title: missingCSP.title, severity: \"high\" as const, category: \"Configuration\",\n file: filePath, line: 1, snippet: getSnippet(content, 1),\n fix: 'Add a CSP meta tag: <meta http-equiv=\"Content-Security-Policy\" content=\"default-src \\'self\\'; script-src \\'self\\'\">'\n }];\n }\n }\n // Skip Electron main process — CSP is typically set in the HTML file (already checked above)\n // Flagging main.ts creates false positives since CSP belongs in index.html for Electron apps\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC021 – IPC Handler Without Path Validation\n// ────────────────────────────────────────────\n\nconst ipcPathTraversal: CustomRule = {\n id: \"VC021\",\n title: \"IPC/File Handler Without Path Validation\",\n severity: \"medium\",\n category: \"Injection\",\n description: \"IPC handlers that read or write files based on renderer-supplied paths without validation allow path traversal attacks, potentially exposing sensitive files like .ssh keys or .env files.\",\n check(content, filePath) {\n if (!/ipcMain\\.handle|ipcMain\\.on/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n // Look for file read/write in IPC handlers without path validation\n const hasFileOps = /readFile|writeFile|readFileSync|writeFileSync|createReadStream|createWriteStream/i.test(content);\n if (!hasFileOps) return [];\n const hasPathValidation = /(?:path\\.resolve|path\\.normalize|startsWith|isAbsolute|\\.includes\\s*\\(\\s*[\"'`]\\.\\.[\"'`]\\s*\\)|allowedPaths|safePath|validatePath|sanitizePath)/i.test(content);\n if (!hasPathValidation) {\n matches.push(...findMatches(content, /ipcMain\\.(?:handle|on)\\s*\\(\\s*[\"'`][^\"'`]*(?:read|write|file|save|load|open|export)[^\"'`]*[\"'`]/gi, ipcPathTraversal, filePath, () =>\n \"Validate file paths in IPC handlers: ensure paths are within an allowed directory (e.g., app.getPath('userData')), reject paths containing '..', and block access to sensitive directories (.ssh, .env, etc).\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC022 – HTML Export Without Sanitization\n// ────────────────────────────────────────────\n\nconst unsanitizedHTMLExport: CustomRule = {\n id: \"VC022\",\n title: \"HTML Export/Render Without Sanitization\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"Generating HTML from user content without sanitization (e.g., DOMPurify) allows stored XSS attacks. Malicious content saved in documents could execute scripts when exported or previewed.\",\n check(content, filePath) {\n if (isTestFile(filePath)) return [];\n // Skip if DOMPurify is imported anywhere in the file\n if (/import.*DOMPurify|require.*DOMPurify|from\\s+['\"]dompurify/i.test(content)) return [];\n // Skip React/Vue component files — JSX is not unsafe HTML concatenation\n if (filePath.match(/\\.(jsx|tsx|vue|svelte)$/) && !/innerHTML|document\\.write|\\.html\\s*=/i.test(content)) return [];\n // Skip files that import DOMPurify or have any sanitizer\n const hasSanitizer = /DOMPurify|sanitize|escapeHtml|escapeHTML|xss|htmlEncode|purify/i.test(content);\n if (hasSanitizer) return [];\n // Only flag files that actually export/write HTML (not just template rendering)\n if (!/(?:export|download|save|write|send).*(?:html|HTML)|\\.innerHTML\\s*=|document\\.write|res\\.send\\s*\\(/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n const htmlBuildPatterns = [\n /`<[^`]*\\$\\{[^}]*(?:content|title|body|text|name|message|description|input|value|data)[^}]*\\}[^`]*>`/gi,\n /[\"']<[^\"']*['\"]\\s*\\+\\s*(?:content|title|body|text|message|data|doc\\.|post\\.|article\\.)/gi,\n ];\n for (const p of htmlBuildPatterns) {\n matches.push(...findMatches(content, p, unsanitizedHTMLExport, filePath, () =>\n \"Sanitize user content before embedding in HTML. Use DOMPurify: DOMPurify.sanitize(content). For plain text, use a function to escape HTML entities (<, >, &, quotes).\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC023 – Prototype Pollution via Storage\n// ────────────────────────────────────────────\n\nconst prototypePollution: CustomRule = {\n id: \"VC023\",\n title: \"Prototype Pollution Risk\",\n severity: \"high\",\n category: \"Injection\",\n description: \"Parsing JSON from localStorage, URL params, or external sources and merging it into objects without validation can lead to prototype pollution, allowing attackers to inject __proto__ or constructor properties.\",\n check(content, filePath) {\n const matches: RuleMatch[] = [];\n // JSON.parse from localStorage/sessionStorage without validation\n const storageParsePatterns = [\n /JSON\\.parse\\s*\\(\\s*(?:localStorage|sessionStorage)\\.getItem/g,\n /JSON\\.parse\\s*\\(\\s*window\\.localStorage/g,\n ];\n const hasValidation = /schema|validate|sanitize|whitelist|allowedKeys|pick\\(|Object\\.freeze|zod|yup|joi|ajv/i.test(content);\n if (hasValidation) return [];\n // Check for object spread/assign from parsed storage\n const hasUnsafeMerge = /Object\\.assign\\s*\\([^)]*JSON\\.parse|\\.\\.\\.JSON\\.parse|\\{.*\\.\\.\\.(?:stored|saved|cached|parsed|data)/i.test(content);\n if (hasUnsafeMerge) {\n matches.push(...findMatches(content, /Object\\.assign\\s*\\([^)]*JSON\\.parse|\\.\\.\\.JSON\\.parse/g, prototypePollution, filePath, () =>\n \"Validate parsed data against an expected schema before merging into objects. Use Object.freeze(), a validation library (Zod, Yup), or manually check for __proto__ and constructor keys.\"\n ));\n }\n for (const p of storageParsePatterns) {\n matches.push(...findMatches(content, p, prototypePollution, filePath, () =>\n \"Validate localStorage data against an expected schema before using it. Malicious extensions or XSS can modify localStorage values.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC024 – Missing File Size Limits\n// ────────────────────────────────────────────\n\nconst missingFileSizeLimits: CustomRule = {\n id: \"VC024\",\n title: \"File Write/Save Without Size Limit\",\n severity: \"medium\",\n category: \"Availability\",\n description: \"File save or upload handlers without size validation can lead to denial-of-service via disk exhaustion or memory exhaustion.\",\n check(content, filePath) {\n if (!/(?:writeFile|save|upload|export)/i.test(filePath) && !/(?:writeFile|writeFileSync|createWriteStream)/i.test(content)) return [];\n // Look for file write operations in handlers\n const hasWriteOps = /(?:ipcMain|app\\.(?:post|put)|router\\.(?:post|put)).*(?:writeFile|save|export)/is.test(content) ||\n /(?:writeFile|writeFileSync)\\s*\\(/g.test(content);\n if (!hasWriteOps) return [];\n const hasSizeCheck = /(?:size|length|byteLength|bytes)\\s*(?:>|>=|<|<=|===)\\s*\\d|maxSize|MAX_SIZE|sizeLimit|content-length/i.test(content);\n if (hasSizeCheck) return [];\n return findMatches(content, /(?:writeFile|writeFileSync)\\s*\\(/g, missingFileSizeLimits, filePath, () =>\n \"Add file size validation before writing. Check content.length or Buffer.byteLength() against a maximum (e.g., 10MB) to prevent disk exhaustion.\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC025 – Unsanitized Export Filenames\n// ────────────────────────────────────────────\n\nconst unsanitizedFilenames: CustomRule = {\n id: \"VC025\",\n title: \"Unsanitized Filename in File Operations\",\n severity: \"medium\",\n category: \"Injection\",\n description: \"Using user-supplied filenames without sanitization in file operations can enable path traversal, overwriting system files, or executing commands via special characters.\",\n check(content, filePath) {\n const matches: RuleMatch[] = [];\n // Look for file operations using variables as filenames\n const patterns = [\n /(?:writeFile|writeFileSync|createWriteStream|rename|copyFile)\\s*\\(\\s*(?:`[^`]*\\$\\{|[^\"'`\\s,]+\\s*\\+)/g,\n /(?:dialog\\.showSaveDialog|saveDialog).*(?:defaultPath|fileName)\\s*:\\s*(?![\"'`])/g,\n /\\.download\\s*=\\s*(?![\"'`])/g,\n ];\n const hasSanitization = /sanitize|cleanFilename|safeFilename|replace\\s*\\(\\s*\\/\\[.*\\]\\//i.test(content);\n if (hasSanitization) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, unsanitizedFilenames, filePath, () =>\n \"Sanitize filenames before use: strip path separators (/ \\\\), special chars, and '..' sequences. Example: name.replace(/[^a-zA-Z0-9._-]/g, '_')\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC026 – Electron Navigation Not Restricted\n// ────────────────────────────────────────────\n\nconst electronNavigationUnrestricted: CustomRule = {\n id: \"VC026\",\n title: \"Electron: External Navigation Not Blocked\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Electron apps that don't block navigation to external URLs or new window creation are vulnerable to phishing and drive-by downloads. Malicious links in app content can redirect the entire app to an attacker's site.\",\n check(content, filePath) {\n if (!/BrowserWindow|electron/i.test(content)) return [];\n if (!/main|index/i.test(filePath)) return [];\n const hasNavBlock = /will-navigate|new-window|setWindowOpenHandler|webContents\\.on.*navigate/i.test(content);\n if (hasNavBlock) return [];\n if (/new\\s+BrowserWindow/i.test(content)) {\n return findMatches(content, /new\\s+BrowserWindow\\s*\\(/g, electronNavigationUnrestricted, filePath, () =>\n \"Block external navigation: win.webContents.on('will-navigate', (e, url) => { if (!url.startsWith('file://')) e.preventDefault(); }); and use setWindowOpenHandler to block new windows.\"\n );\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC027 – Missing Security Meta Tags\n// ────────────────────────────────────────────\n\nconst missingSecurityMeta: CustomRule = {\n id: \"VC027\",\n title: \"Missing Security Meta Tags / Headers\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"HTML pages without X-Content-Type-Options, referrer policy, or other security meta tags are more susceptible to MIME-sniffing attacks and information leakage.\",\n check(content, filePath) {\n if (!filePath.match(/\\.(html|htm)$/)) return [];\n const matches: RuleMatch[] = [];\n if (!/X-Content-Type-Options/i.test(content) && !/<meta[^>]*nosniff/i.test(content)) {\n matches.push({\n rule: \"VC027\", title: \"Missing X-Content-Type-Options Header\", severity: \"medium\" as const,\n category: \"Configuration\", file: filePath, line: 1, snippet: getSnippet(content, 1),\n fix: 'Add <meta http-equiv=\"X-Content-Type-Options\" content=\"nosniff\"> to prevent MIME-type sniffing.'\n });\n }\n if (!/referrer/i.test(content)) {\n matches.push({\n rule: \"VC027\", title: \"Missing Referrer Policy\", severity: \"medium\" as const,\n category: \"Configuration\", file: filePath, line: 1, snippet: getSnippet(content, 1),\n fix: 'Add <meta name=\"referrer\" content=\"no-referrer\"> or \"strict-origin-when-cross-origin\" to limit referrer leakage.'\n });\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC028 – Unvalidated API Parameters\n// ────────────────────────────────────────────\n\nconst unvalidatedAPIParams: CustomRule = {\n id: \"VC028\",\n title: \"Unvalidated API Request Parameters\",\n severity: \"high\",\n category: \"Injection\",\n description: \"API requests constructed with unvalidated user input (API keys, model names, URLs) can be exploited for injection attacks or unauthorized access to different API models/endpoints.\",\n check(content, filePath) {\n const matches: RuleMatch[] = [];\n // API key passed without format validation\n const apiKeyPatterns = [\n /(?:apiKey|api_key|authorization)\\s*[:=]\\s*(?:req\\.body|req\\.query|params|input|formData|body)\\./gi,\n /headers\\s*:\\s*\\{[^}]*Authorization\\s*:\\s*(?![\"'`]Bearer\\s)/gi,\n ];\n const hasValidation = /validate|sanitize|regex|test\\(|match\\(|pattern|allowList|whitelist|enum|includes\\(/i.test(content);\n if (hasValidation) return [];\n // Model selection without allowlist\n if (/model\\s*[:=]\\s*(?:req\\.body|params|input|body)\\./i.test(content) || /model\\s*[:=]\\s*(?![\"'`])[a-z]/i.test(content)) {\n const hasModelValidation = /allowedModels|validModels|models\\s*\\.\\s*includes|model.*(?:===|!==|includes)/i.test(content);\n if (!hasModelValidation && /(?:openai|anthropic|claude|gpt|llm)/i.test(content)) {\n matches.push(...findMatches(content, /model\\s*[:=]\\s*(?:req\\.body|params|input|body)\\./gi, unvalidatedAPIParams, filePath, () =>\n \"Validate model selection against an allowlist of approved models. Example: const ALLOWED_MODELS = ['gpt-4', 'claude-3']; if (!ALLOWED_MODELS.includes(model)) throw new Error('Invalid model');\"\n ));\n }\n }\n for (const p of apiKeyPatterns) {\n matches.push(...findMatches(content, p, unvalidatedAPIParams, filePath, () =>\n \"Validate API key format before using it (e.g., check prefix and length). Never pass user-supplied API keys directly to third-party services without validation.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC029 – Unvalidated Event/Message Data\n// ────────────────────────────────────────────\n\nconst unvalidatedEventData: CustomRule = {\n id: \"VC029\",\n title: \"Unvalidated Event or PostMessage Data\",\n severity: \"medium\",\n category: \"Injection\",\n description: \"Custom events, postMessage, or IPC message data used without type-checking can lead to injection attacks or unexpected behavior when malicious data is sent through event channels.\",\n check(content, filePath) {\n const matches: RuleMatch[] = [];\n // addEventListener('message') without origin check\n if (/addEventListener\\s*\\(\\s*[\"'`]message[\"'`]/i.test(content)) {\n if (!/event\\.origin|e\\.origin|message\\.origin/i.test(content)) {\n matches.push(...findMatches(content, /addEventListener\\s*\\(\\s*[\"'`]message[\"'`]/g, unvalidatedEventData, filePath, () =>\n \"Always verify event.origin in message event handlers to prevent cross-origin attacks. Example: if (event.origin !== 'https://trusted.com') return;\"\n ));\n }\n }\n // dispatchEvent with custom data inserted without validation\n if (/new\\s+CustomEvent\\s*\\(/i.test(content) || /ipcRenderer\\.send/i.test(content)) {\n const hasTypeCheck = /typeof\\s|instanceof|z\\.|schema|validate|Number\\.isFinite|parseInt|parseFloat/i.test(content);\n if (!hasTypeCheck) {\n matches.push(...findMatches(content, /new\\s+CustomEvent\\s*\\(/g, unvalidatedEventData, filePath, () =>\n \"Type-check custom event data before using it. Validate that data.detail contains expected types to prevent injection.\"\n ));\n }\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC030 – Insecure Deserialization\n// ────────────────────────────────────────────\n\nconst insecureDeserialization: CustomRule = {\n id: \"VC030\",\n title: \"Insecure Deserialization\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"Deserializing untrusted data (pickle, unserialize, yaml.load) can execute arbitrary code. Attackers craft malicious payloads to gain remote code execution.\",\n check(content, filePath) {\n const matches: RuleMatch[] = [];\n const patterns = [\n // Python pickle\n /pickle\\.loads?\\s*\\(/g,\n /cPickle\\.loads?\\s*\\(/g,\n // PHP unserialize\n /unserialize\\s*\\(/g,\n // Ruby Marshal\n /Marshal\\.load\\s*\\(/g,\n // YAML unsafe load (Python)\n /yaml\\.load\\s*\\([^)]*(?!Loader\\s*=\\s*yaml\\.SafeLoader)/g,\n /yaml\\.unsafe_load\\s*\\(/g,\n // Java ObjectInputStream\n /ObjectInputStream\\s*\\(/g,\n // Node.js node-serialize\n /serialize\\.unserialize\\s*\\(/g,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, insecureDeserialization, filePath, () =>\n \"Never deserialize untrusted data. Use JSON instead of pickle/Marshal/unserialize. For YAML, use yaml.safe_load(). Validate and sanitize all input before deserialization.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC031 – Hardcoded JWT Secret\n// ────────────────────────────────────────────\n\nconst hardcodedJWTSecret: CustomRule = {\n id: \"VC031\",\n title: \"Hardcoded JWT Secret\",\n severity: \"critical\",\n category: \"Secrets\",\n description: \"JWT tokens signed with a hardcoded string secret can be forged by anyone who reads the source code.\",\n check(content, filePath) {\n if (filePath.endsWith(\".example\") || filePath.endsWith(\".template\") || filePath.includes(\"test\")) return [];\n const patterns = [\n /jwt\\.sign\\s*\\([^,]+,\\s*[\"'`][^\"'`]{3,}[\"'`]/g,\n /jwt\\.verify\\s*\\([^,]+,\\s*[\"'`][^\"'`]{3,}[\"'`]/g,\n /jsonwebtoken.*secret\\s*[:=]\\s*[\"'`][^\"'`]{3,}[\"'`]/gi,\n /JWT_SECRET\\s*[:=]\\s*[\"'`][^\"'`]{3,}[\"'`]/g,\n ];\n const matches: RuleMatch[] = [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, hardcodedJWTSecret, filePath, () =>\n \"Move JWT secret to an environment variable: jwt.sign(payload, process.env.JWT_SECRET). Use a strong, random secret (256+ bits).\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC032 – Missing HTTPS Enforcement\n// ────────────────────────────────────────────\n\nconst missingHTTPS: CustomRule = {\n id: \"VC032\",\n title: \"Missing HTTPS Enforcement\",\n severity: \"high\",\n category: \"Configuration\",\n description: \"HTTP URLs in production code, missing HSTS headers, or insecure redirect configurations expose data to man-in-the-middle attacks.\",\n check(content, filePath) {\n if (filePath.endsWith(\".example\") || filePath.includes(\"test\") || filePath.includes(\"README\")) return [];\n if (filePath.match(/\\.(md|txt)$/)) return [];\n const matches: RuleMatch[] = [];\n // Skip standard XML/HTML doctypes, DTDs, schema URIs, namespace URLs\n if (/<!DOCTYPE|xmlns|\\.dtd|\\.xsd/i.test(content) && !/fetch|axios|request|http\\.get/i.test(content)) return [];\n // Hardcoded http:// URLs to non-local hosts (excluding standard schema/namespace URIs)\n const httpPattern = /[\"'`]http:\\/\\/(?!localhost|127\\.0\\.0\\.1|0\\.0\\.0\\.0|192\\.168\\.|10\\.|172\\.(?:1[6-9]|2\\d|3[01])\\.|www\\.w3\\.org|www\\.apple\\.com\\/DTDs|schemas?\\.|xml\\.org|purl\\.org|ns\\.adobe|xmlpull\\.org|java\\.sun\\.com)[^\"'`\\s]+[\"'`]/g;\n const rawMatches = findMatches(content, httpPattern, missingHTTPS, filePath, () =>\n \"Use https:// instead of http:// for all production URLs. Add HSTS header: Strict-Transport-Security: max-age=31536000; includeSubDomains\"\n );\n // Skip DOCTYPE/DTD URLs\n for (const rm of rawMatches) {\n const lineStart = content.lastIndexOf(\"\\n\", content.split(\"\\n\").slice(0, rm.line - 1).join(\"\\n\").length) + 1;\n const lineEnd = content.indexOf(\"\\n\", lineStart + 1);\n const matchText = content.substring(lineStart, lineEnd === -1 ? content.length : lineEnd);\n if (/DTD|DOCTYPE|w3\\.org|apple\\.com\\/DTDs/i.test(matchText)) continue;\n matches.push(rm);\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC033 – Exposed Debug/Dev Mode\n// ────────────────────────────────────────────\n\nconst exposedDebugMode: CustomRule = {\n id: \"VC033\",\n title: \"Debug/Development Mode Exposed\",\n severity: \"high\",\n category: \"Configuration\",\n description: \"Debug mode, verbose logging, or development configuration left in production code exposes internal details and may enable debug endpoints.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.endsWith(\".example\") || filePath.includes(\"node_modules\")) return [];\n if (filePath.match(/\\.env\\.development$/)) return []; // Expected in dev env files\n const matches: RuleMatch[] = [];\n const patterns = [\n // Debug flags set to true\n /DEBUG\\s*[:=]\\s*(?:true|1|[\"'`]true[\"'`]|[\"'`]\\*[\"'`])/g,\n // Django DEBUG\n /DEBUG\\s*=\\s*True/g,\n // Flask/Express debug mode\n /app\\.debug\\s*=\\s*True/g,\n /app\\.run\\s*\\([^)]*debug\\s*=\\s*True/g,\n // Source maps in production\n /devtool\\s*:\\s*[\"'`](?:eval|cheap|source-map|inline-source-map)[\"'`]/g,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, exposedDebugMode, filePath, () =>\n \"Disable debug mode in production. Use environment variables: DEBUG = process.env.NODE_ENV !== 'production'. Remove source maps from production builds.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC034 – Insecure Randomness\n// ────────────────────────────────────────────\n\nconst insecureRandomness: CustomRule = {\n id: \"VC034\",\n title: \"Insecure Randomness for Security-Sensitive Values\",\n severity: \"high\",\n category: \"Cryptography\",\n description: \"Math.random() is not cryptographically secure. Using it for tokens, session IDs, passwords, or OTPs makes them predictable.\",\n check(content, filePath) {\n if (isTestFile(filePath)) return [];\n // Only flag if Math.random is actually used (not just mentioned)\n if (!/Math\\.random\\s*\\(\\s*\\)/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n // Math.random used in security-critical assignments (narrower: require direct assignment on same line)\n const securityContext = /(?:token|secret|session|password|otp|nonce|salt|csrf|auth)\\s*[:=]\\s*.*Math\\.random/gi;\n matches.push(...findMatches(content, securityContext, insecureRandomness, filePath, () =>\n \"Use crypto.randomUUID() or crypto.getRandomValues() for security-sensitive values. Math.random() is predictable.\"\n ));\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC035 – Open Redirect via URL Params\n// ────────────────────────────────────────────\n\nconst openRedirectParams: CustomRule = {\n id: \"VC035\",\n title: \"Open Redirect via URL Parameters\",\n severity: \"high\",\n category: \"Injection\",\n description: \"Redirect parameters like ?redirect_url=, ?return_to=, ?next= passed directly to redirects enable phishing attacks.\",\n check(content, filePath) {\n const matches: RuleMatch[] = [];\n const patterns = [\n // Reading redirect-like query params and using in redirect\n /(?:redirect_url|redirect_uri|return_to|return_url|next|callback_url|continue|goto|target|dest|destination|forward|redir)\\s*(?:=|:)\\s*(?:req\\.query|req\\.params|searchParams|query|params)\\./gi,\n /redirect\\s*\\(\\s*(?:req\\.query|req\\.params|searchParams\\.get)\\s*\\(\\s*[\"'`](?:redirect|return|next|callback|url|goto)/gi,\n ];\n const hasValidation = /allowedUrls|allowedDomains|allowedHosts|validUrl|safeDomain|whitelist|startsWith.*https|new URL.*hostname/i.test(content);\n if (hasValidation) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, openRedirectParams, filePath, () =>\n \"Validate redirect URLs against an allowlist of trusted domains. Use: const url = new URL(input); if (!ALLOWED_HOSTS.includes(url.hostname)) reject.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC036 – Missing Error Boundary (React)\n// ────────────────────────────────────────────\n\nconst missingErrorBoundary: CustomRule = {\n id: \"VC036\",\n title: \"React App Missing Error Boundary\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"React apps without error boundaries display raw stack traces and component tree info to users when crashes occur, leaking internal details.\",\n check(content, filePath) {\n // Only check entry points — main.tsx/main.jsx/index.tsx or layout files\n // Skip App.tsx — ErrorBoundary is typically in main.tsx wrapping <App />\n if (!filePath.match(/(?:layout|_app|main|index)\\.[jt]sx?$/) || filePath.match(/App\\.[jt]sx?$/)) return [];\n // Skip Electron main process files — they're Node.js, not React\n if (/(?:BrowserWindow|electron|ipcMain|app\\.on\\s*\\(\\s*[\"']ready)/i.test(content)) return [];\n // Skip main process files that reference Electron\n if (/(?:main\\/main|main\\.ts$|main\\.js$)/.test(filePath) && /(?:electron|BrowserWindow)/i.test(content)) return [];\n // Skip files without React imports — not a React file\n if (!/(?:import.*react|from\\s+['\"]react|require.*react)/i.test(content)) return [];\n // Must actually contain React code\n if (!/(?:React|react-dom|createRoot|ReactDOM|jsx|tsx)/i.test(content)) return [];\n const hasErrorBoundary = /ErrorBoundary|componentDidCatch|getDerivedStateFromError|error-boundary/i.test(content);\n if (hasErrorBoundary) return [];\n // Check if it renders React components (typical entry point pattern)\n if (/createRoot|ReactDOM\\.render|<[A-Z]/i.test(content)) {\n return [{\n rule: \"VC036\", title: missingErrorBoundary.title, severity: \"medium\" as const, category: \"Configuration\",\n file: filePath, line: 1, snippet: getSnippet(content, 1),\n fix: \"Wrap your app in an ErrorBoundary component to catch rendering errors gracefully. Use react-error-boundary or create a class component with componentDidCatch.\"\n }];\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC037 – Exposed Stack Traces in API\n// ────────────────────────────────────────────\n\nconst exposedStackTraces: CustomRule = {\n id: \"VC037\",\n title: \"Stack Traces Exposed in API Responses\",\n severity: \"medium\",\n category: \"Information Leakage\",\n description: \"Returning error.stack or detailed error messages in API responses reveals internal code paths, file structure, and dependencies to attackers.\",\n check(content, filePath) {\n const isApiFile = /(?:\\/api\\/|routes?\\/|controllers?\\/|server\\.|middleware)/i.test(filePath);\n if (!isApiFile) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n // Sending stack trace in response\n /(?:res\\.(?:json|send|status)|c\\.json|return.*json)\\s*\\([^)]*(?:err\\.stack|error\\.stack|e\\.stack)/gi,\n /(?:res\\.(?:json|send|status)|c\\.json)\\s*\\([^)]*(?:err\\.message|error\\.message|e\\.message)/gi,\n // Express-style error with stack\n /(?:message|error)\\s*:\\s*(?:err|error|e)\\.(?:stack|message)/gi,\n ];\n const hasEnvCheck = /process\\.env\\.NODE_ENV\\s*(?:===|!==)\\s*[\"'`]production[\"'`]|NODE_ENV/i.test(content);\n if (hasEnvCheck) return []; // They're conditionally showing errors\n for (const p of patterns) {\n matches.push(...findMatches(content, p, exposedStackTraces, filePath, () =>\n \"Never expose error.stack or error.message to clients in production. Return generic error messages: { error: 'Something went wrong' }. Log details server-side only.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC038 – Insecure File Upload Type\n// ────────────────────────────────────────────\n\nconst insecureFileUpload: CustomRule = {\n id: \"VC038\",\n title: \"Insecure File Upload Validation\",\n severity: \"high\",\n category: \"Injection\",\n description: \"File uploads validated only by extension (not MIME type or content) allow attackers to upload executable files disguised as images or documents.\",\n check(content, filePath) {\n if (!/upload|multer|formidable|busboy|multipart/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n // Check for extension-only validation\n const hasExtCheck = /\\.(?:endsWith|match|test)\\s*\\([^)]*(?:\\.jpg|\\.png|\\.pdf|\\.doc|ext)/i.test(content);\n const hasMimeCheck = /mimetype|content-type|file\\.type|mime|magic\\.detect|file-type/i.test(content);\n if (hasExtCheck && !hasMimeCheck) {\n matches.push(...findMatches(content, /upload|multer|formidable|busboy/gi, insecureFileUpload, filePath, () =>\n \"Validate file uploads by MIME type AND magic bytes, not just extension. Use the 'file-type' package to detect actual file type from content. Also enforce size limits.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC039 – Missing Dependency Lock File\n// ────────────────────────────────────────────\n\nconst missingLockFile: CustomRule = {\n id: \"VC039\",\n title: \"Missing Dependency Lock File\",\n severity: \"medium\",\n category: \"Supply Chain\",\n description: \"Without a lockfile (package-lock.json, pnpm-lock.yaml, yarn.lock), dependency versions are unpinned and vulnerable to supply chain attacks via version substitution.\",\n check(content, filePath) {\n // Only check .gitignore for lock files being ignored\n if (!filePath.endsWith(\".gitignore\")) return [];\n const ignoresLock = /package-lock\\.json|pnpm-lock\\.yaml|yarn\\.lock/i.test(content);\n if (ignoresLock) {\n return findMatches(content, /(?:package-lock\\.json|pnpm-lock\\.yaml|yarn\\.lock)/gi, missingLockFile, filePath, () =>\n \"Remove the lockfile from .gitignore. Lockfiles should be committed to prevent supply chain attacks. They ensure exact versions are installed across all environments.\"\n );\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC040 – Exposed .git Directory\n// ────────────────────────────────────────────\n\nconst exposedGitDir: CustomRule = {\n id: \"VC040\",\n title: \"Exposed .git Directory via Web Server\",\n severity: \"critical\",\n category: \"Information Leakage\",\n description: \"Web server configs that don't block access to .git directories expose your entire source code, commit history, secrets, and credentials.\",\n check(content, filePath) {\n // Check web server configs\n if (!filePath.match(/(?:nginx|apache|httpd|caddy|\\.htaccess|vercel\\.json|netlify\\.toml|server\\.[jt]s)/i)) return [];\n // For static file servers, check they block .git\n if (/(?:static|serve|express\\.static|serveStatic|public)/i.test(content)) {\n const blocksGit = /\\.git|dotfiles|hidden/i.test(content);\n if (!blocksGit) {\n return findMatches(content, /(?:static|serve|express\\.static|serveStatic)\\s*\\(/g, exposedGitDir, filePath, () =>\n \"Block access to .git and other dotfiles in your static file server config. For Express: app.use('/.git', (req, res) => res.status(403).end()). For Nginx: location ~ /\\\\.git { deny all; }\"\n );\n }\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC041 – Server-Side Request Forgery (SSRF)\n// ────────────────────────────────────────────\n\nconst ssrfVulnerability: CustomRule = {\n id: \"VC041\",\n title: \"Potential Server-Side Request Forgery (SSRF)\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"Fetching URLs from user input without validation allows attackers to access internal services, cloud metadata endpoints (169.254.169.254), and private networks.\",\n check(content, filePath) {\n if (isTestFile(filePath)) return [];\n // Only check server-side files\n const isServerFile = /(?:\\/api\\/|routes?\\/|controllers?\\/|server\\.|handler|middleware)/i.test(filePath);\n if (!isServerFile) return [];\n const matches: RuleMatch[] = [];\n // Only flag direct user input passed to fetch — narrower pattern\n const patterns = [\n /(?:fetch|axios\\.get|axios\\.post|axios|got|request|http\\.get|https\\.get)\\s*\\(\\s*(?:req\\.(?:body|query|params))\\./gi,\n ];\n const hasValidation = /allowedHosts|allowedDomains|allowedUrls|safeDomain|whitelist|urlValidator|new URL.*hostname.*includes|isAllowedUrl|validateUrl|isValidUrl/i.test(content);\n if (hasValidation) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, ssrfVulnerability, filePath, () =>\n \"Validate URLs against an allowlist before fetching. Block internal IPs: 127.0.0.1, 10.x, 172.16-31.x, 192.168.x, 169.254.169.254 (cloud metadata). Use: const url = new URL(input); if (!ALLOWED_HOSTS.includes(url.hostname)) throw new Error('Blocked');\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC042 – Mass Assignment\n// ────────────────────────────────────────────\n\nconst massAssignment: CustomRule = {\n id: \"VC042\",\n title: \"Mass Assignment Vulnerability\",\n severity: \"high\",\n category: \"Authorization\",\n description: \"Spreading or assigning request body directly into database models allows attackers to set fields they shouldn't (e.g., isAdmin, role, verified).\",\n check(content, filePath) {\n const isApiFile = /(?:\\/api\\/|routes?\\/|controllers?\\/|server\\.|handler)/i.test(filePath);\n if (!isApiFile) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n // Object.assign(model, req.body)\n /Object\\.assign\\s*\\(\\s*(?:user|account|profile|record|doc|model|entity)[^,]*,\\s*(?:req\\.body|body|input|data)\\s*\\)/gi,\n // Spread req.body into create/update\n /(?:create|update|insert|save|findOneAndUpdate|updateOne|upsert)\\s*\\(\\s*\\{[^}]*\\.\\.\\.(?:req\\.body|body|input|data)/gi,\n // Direct req.body into DB\n /(?:create|insert|save)\\s*\\(\\s*(?:req\\.body|body)\\s*\\)/gi,\n ];\n const hasSanitization = /pick\\(|omit\\(|allowedFields|sanitize|whitelist|permit|strong_params/i.test(content);\n if (hasSanitization) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, massAssignment, filePath, () =>\n \"Never pass req.body directly to database operations. Explicitly pick allowed fields: const { name, email } = req.body; await db.create({ name, email });\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC043 – Timing Attack on Comparison\n// ────────────────────────────────────────────\n\nconst timingAttack: CustomRule = {\n id: \"VC043\",\n title: \"Timing-Unsafe Secret Comparison\",\n severity: \"medium\",\n category: \"Cryptography\",\n description: \"Using === to compare secrets, tokens, or hashes leaks information via timing side-channels. Attackers can determine the correct value one character at a time.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n const matches: RuleMatch[] = [];\n // Direct comparison of secrets/tokens/hashes\n const patterns = [\n /(?:token|secret|hash|digest|signature|hmac|apiKey|api_key)\\s*(?:===|!==)\\s*(?:req\\.|body\\.|params\\.|query\\.|input)/gi,\n /(?:req\\.|body\\.|params\\.|query\\.|input)[\\w.]*(?:token|secret|hash|digest|signature|hmac)\\s*(?:===|!==)/gi,\n ];\n const hasTimingSafe = /timingSafeEqual|constantTimeEqual|safeCompare|secureCompare/i.test(content);\n if (hasTimingSafe) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, timingAttack, filePath, () =>\n \"Use crypto.timingSafeEqual() for comparing secrets: crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b)). This prevents timing-based side-channel attacks.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC044 – Log Injection\n// ────────────────────────────────────────────\n\nconst logInjection: CustomRule = {\n id: \"VC044\",\n title: \"Potential Log Injection\",\n severity: \"medium\",\n category: \"Injection\",\n description: \"Logging unsanitized user input allows attackers to forge log entries, inject malicious content, or exploit log aggregation systems via newlines and special characters.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n const isServerFile = /(?:\\/api\\/|routes?\\/|controllers?\\/|server\\.|middleware|handler)/i.test(filePath);\n if (!isServerFile) return [];\n const matches: RuleMatch[] = [];\n // console.log/warn/error with req.body/query/params directly\n const patterns = [\n /console\\.(?:log|warn|error|info)\\s*\\([^)]*(?:req\\.body|req\\.query|req\\.params|req\\.headers)\\s*\\)/gi,\n /(?:logger|log)\\.(?:info|warn|error|debug)\\s*\\([^)]*(?:req\\.body|req\\.query|req\\.params)\\s*\\)/gi,\n ];\n const hasSanitization = /sanitize|escape|JSON\\.stringify|replace.*\\\\n/i.test(content);\n if (hasSanitization) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, logInjection, filePath, () =>\n \"Sanitize user input before logging: strip newlines and control characters. Use JSON.stringify() or a structured logger (e.g., pino, winston) that escapes values automatically.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC045 – Weak Password Requirements\n// ────────────────────────────────────────────\n\nconst weakPasswordRequirements: CustomRule = {\n id: \"VC045\",\n title: \"Weak Password Requirements\",\n severity: \"high\",\n category: \"Authentication\",\n description: \"Registration or password-change endpoints without minimum length or complexity validation allow weak passwords that are easily brute-forced.\",\n check(content, filePath) {\n if (isTestFile(filePath)) return [];\n if (!/(?:password|passwd|pwd)/i.test(content)) return [];\n if (!/(?:register|signup|sign.up|createUser|create.user|changePassword|resetPassword|set.password)/i.test(content) &&\n !/(?:\\/api\\/|routes?\\/|controllers?\\/)/i.test(filePath)) return [];\n // Check for validation anywhere in the file — broader detection of mitigation\n const hasValidation = /(?:password|pwd).*(?:\\.length|minLength|minlength|min_length)\\s*(?:>=?|<|>)\\s*\\d|(?:password|pwd).*(?:match|test|regex|pattern)|zxcvbn|password-validator|passwordStrength|isStrongPassword|joi\\.|yup\\.|zod\\.|validate|schema/i.test(content);\n if (hasValidation) return [];\n const hasPasswordHandling = /(?:password|pwd)\\s*[:=]\\s*(?:req\\.body|body|input|params|args)\\./i.test(content);\n if (!hasPasswordHandling) return [];\n return findMatches(content, /(?:password|pwd)\\s*[:=]\\s*(?:req\\.body|body|input|params|args)\\./gi, weakPasswordRequirements, filePath, () =>\n \"Enforce minimum password requirements: at least 8 characters, mix of letters/numbers/symbols. Use a library like zxcvbn for strength estimation.\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC046 – Session Fixation\n// ────────────────────────────────────────────\n\nconst sessionFixation: CustomRule = {\n id: \"VC046\",\n title: \"Session Fixation Risk\",\n severity: \"high\",\n category: \"Authentication\",\n description: \"Not regenerating session IDs after login allows attackers to pre-set a session ID and hijack the authenticated session.\",\n check(content, filePath) {\n if (!/(?:login|signin|sign.in|authenticate)/i.test(content)) return [];\n if (!/session/i.test(content)) return [];\n const hasRegenerate = /regenerate|destroy.*create|req\\.session\\.id\\s*=|session\\.regenerateId|rotateSession/i.test(content);\n if (hasRegenerate) return [];\n const hasLogin = /(?:login|signin|authenticate)\\s*(?:=|:|\\()/i.test(content);\n if (!hasLogin) return [];\n return findMatches(content, /(?:login|signin|authenticate)\\s*(?:=|:|\\()/gi, sessionFixation, filePath, () =>\n \"Regenerate the session ID after successful login: req.session.regenerate() (Express) or equivalent. This prevents session fixation attacks.\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC047 – Missing Brute Force Protection\n// ────────────────────────────────────────────\n\nconst missingBruteForce: CustomRule = {\n id: \"VC047\",\n title: \"Login Without Brute Force Protection\",\n severity: \"high\",\n category: \"Authentication\",\n description: \"Login endpoints without rate limiting, account lockout, or progressive delays are vulnerable to credential stuffing and brute force attacks.\",\n check(content, filePath) {\n const isLoginFile = /(?:login|signin|sign.in|auth)/i.test(filePath) || /(?:login|signin|authenticate).*(?:post|handler|route)/i.test(content);\n if (!isLoginFile) return [];\n if (!/(?:password|credential)/i.test(content)) return [];\n const hasBruteForce = /rate.?limit|throttle|lockout|maxAttempts|max_attempts|failedAttempts|loginAttempts|brute|express-brute|express-rate-limit|slowDown/i.test(content);\n if (hasBruteForce) return [];\n return findMatches(content, /\\.(post|handler)\\s*\\([^)]*(?:login|signin|auth)/gi, missingBruteForce, filePath, () =>\n \"Add brute force protection to login endpoints: rate limiting (5 attempts/minute), progressive delays, or account lockout after N failures. Use express-rate-limit or similar.\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC048 – NoSQL Injection\n// ────────────────────────────────────────────\n\nconst nosqlInjection: CustomRule = {\n id: \"VC048\",\n title: \"Potential NoSQL Injection\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"Passing unsanitized user input directly into MongoDB/NoSQL queries allows attackers to bypass authentication, extract data, or modify queries using operators like $gt, $ne, $regex.\",\n check(content, filePath) {\n if (!/(?:mongo|mongoose|findOne|findById|find\\(|collection|aggregate)/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n // Direct req.body in MongoDB queries\n /\\.find(?:One)?\\s*\\(\\s*(?:req\\.body|body|input|params)\\s*\\)/gi,\n /\\.find(?:One)?\\s*\\(\\s*\\{[^}]*:\\s*(?:req\\.body|body|input|params)\\./gi,\n // $where with user input\n /\\$where\\s*:\\s*(?![\"'`])/g,\n // Direct variable in query without sanitization\n /\\.(?:findOne|findById|deleteOne|updateOne|findOneAndUpdate)\\s*\\(\\s*\\{[^}]*:\\s*(?:req\\.(?:body|query|params))\\./gi,\n ];\n const hasSanitization = /sanitize|escape|mongo-sanitize|express-mongo-sanitize|validator|typeof.*===.*string/i.test(content);\n if (hasSanitization) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, nosqlInjection, filePath, () =>\n \"Sanitize MongoDB query inputs: use express-mongo-sanitize, validate types (ensure strings aren't objects), and avoid $where. Example: if (typeof input !== 'string') throw new Error('Invalid input');\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC049 – Exposed DB Credentials in Config\n// ────────────────────────────────────────────\n\nconst exposedDBCredentials: CustomRule = {\n id: \"VC049\",\n title: \"Database Credentials in Config File\",\n severity: \"critical\",\n category: \"Secrets\",\n description: \"Database connection strings with embedded usernames and passwords in committed config files expose credentials to anyone with repo access.\",\n check(content, filePath) {\n if (filePath.endsWith(\".example\") || filePath.endsWith(\".template\")) return [];\n if (!filePath.match(/(?:config|setting|database|db|knexfile|sequelize|drizzle|prisma)/i) && !filePath.match(/\\.(json|yaml|yml|toml|js|ts)$/)) return [];\n if (filePath.match(/\\.env/)) return []; // Handled by VC002\n const patterns = [\n // Connection strings with credentials\n /(?:host|server|database|db).*(?:password|passwd|pwd)\\s*[:=]\\s*[\"'`][^\"'`]{3,}[\"'`]/gi,\n // Inline connection URLs with credentials\n /(?:connection|database|db).*(?:postgres|mysql|mongodb|redis):\\/\\/[^:]+:[^@]+@/gi,\n ];\n const matches: RuleMatch[] = [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, exposedDBCredentials, filePath, () =>\n \"Move database credentials to environment variables. Use: process.env.DATABASE_URL instead of hardcoding connection strings in config files.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC050 – Missing DB Connection Encryption\n// ────────────────────────────────────────────\n\nconst missingDBEncryption: CustomRule = {\n id: \"VC050\",\n title: \"Database Connection Without SSL/TLS\",\n severity: \"high\",\n category: \"Configuration\",\n description: \"Database connections without SSL/TLS encryption transmit credentials and data in plaintext, allowing eavesdropping on the network.\",\n check(content, filePath) {\n if (!/(?:createConnection|createPool|createClient|connect|new.*Client|knex|sequelize|drizzle)/i.test(content)) return [];\n if (!/(?:postgres|mysql|mariadb|pg|mongo)/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n // SSL explicitly disabled\n const sslDisabled = [\n /ssl\\s*:\\s*false/gi,\n /sslmode\\s*[:=]\\s*[\"'`]?disable[\"'`]?/gi,\n /rejectUnauthorized\\s*:\\s*false/gi,\n ];\n for (const p of sslDisabled) {\n matches.push(...findMatches(content, p, missingDBEncryption, filePath, () =>\n \"Enable SSL/TLS for database connections: { ssl: { rejectUnauthorized: true } }. In production, always verify server certificates.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC051 – GraphQL Introspection Enabled\n// ────────────────────────────────────────────\n\nconst graphqlIntrospection: CustomRule = {\n id: \"VC051\",\n title: \"GraphQL Introspection Enabled in Production\",\n severity: \"medium\",\n category: \"Information Leakage\",\n description: \"GraphQL introspection exposes your entire API schema, types, queries, and mutations to attackers, making it easy to find attack vectors.\",\n check(content, filePath) {\n if (!/graphql/i.test(content) && !/graphql/i.test(filePath)) return [];\n const matches: RuleMatch[] = [];\n // Introspection explicitly enabled or not disabled\n if (/introspection\\s*:\\s*true/i.test(content)) {\n matches.push(...findMatches(content, /introspection\\s*:\\s*true/gi, graphqlIntrospection, filePath, () =>\n \"Disable GraphQL introspection in production: introspection: process.env.NODE_ENV !== 'production'. This prevents schema exposure.\"\n ));\n }\n // GraphQL server setup without introspection config\n if (/(?:ApolloServer|GraphQLServer|createYoga|buildSchema|makeExecutableSchema)\\s*\\(/i.test(content)) {\n if (!/introspection/i.test(content)) {\n matches.push(...findMatches(content, /(?:ApolloServer|GraphQLServer|createYoga)\\s*\\(/gi, graphqlIntrospection, filePath, () =>\n \"Explicitly disable introspection in production: new ApolloServer({ introspection: process.env.NODE_ENV !== 'production' })\"\n ));\n }\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC052 – Missing Request Size Limit\n// ────────────────────────────────────────────\n\nconst missingRequestSizeLimit: CustomRule = {\n id: \"VC052\",\n title: \"Missing Request Body Size Limit\",\n severity: \"medium\",\n category: \"Availability\",\n description: \"Express/Hono/Fastify servers without request body size limits are vulnerable to denial-of-service via oversized payloads that exhaust memory.\",\n check(content, filePath) {\n if (!/(?:server|app|index|main)\\.[jt]sx?$/.test(filePath)) return [];\n if (!/(?:express|hono|fastify|koa)/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n // express.json() without limit\n if (/express\\.json\\s*\\(\\s*\\)/g.test(content)) {\n matches.push(...findMatches(content, /express\\.json\\s*\\(\\s*\\)/g, missingRequestSizeLimit, filePath, () =>\n \"Set a body size limit: express.json({ limit: '1mb' }). Without this, attackers can send huge payloads to crash your server.\"\n ));\n }\n // bodyParser without limit\n if (/bodyParser\\.json\\s*\\(\\s*\\)/g.test(content)) {\n matches.push(...findMatches(content, /bodyParser\\.json\\s*\\(\\s*\\)/g, missingRequestSizeLimit, filePath, () =>\n \"Set a body size limit: bodyParser.json({ limit: '1mb' }).\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC053 – Hardcoded IP/Host Allowlist\n// ────────────────────────────────────────────\n\nconst hardcodedIPAllowlist: CustomRule = {\n id: \"VC053\",\n title: \"Hardcoded IP or Host Allowlist\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Hardcoded IP addresses or hostnames in allowlists are brittle and hard to update. They should be in environment variables or configuration files.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\") || filePath.match(/\\.(md|txt)$/)) return [];\n const matches: RuleMatch[] = [];\n // Arrays of IPs used in access control\n const patterns = [\n /(?:allowedIPs|allowed_ips|whitelist|allowlist|trustedHosts)\\s*[:=]\\s*\\[\\s*[\"'`]\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}/gi,\n /(?:allowedIPs|allowed_ips|whitelist|allowlist|trustedHosts)\\s*[:=]\\s*\\[\\s*[\"'`][\\w.-]+\\.(?:com|net|org|io)/gi,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, hardcodedIPAllowlist, filePath, () =>\n \"Move IP/host allowlists to environment variables or a config file: const allowed = process.env.ALLOWED_IPS?.split(',') || [];\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC054 – Sensitive Data in localStorage\n// ────────────────────────────────────────────\n\nconst sensitiveLocalStorage: CustomRule = {\n id: \"VC054\",\n title: \"Sensitive Data in localStorage\",\n severity: \"high\",\n category: \"Secrets\",\n description: \"Storing tokens, passwords, or secrets in localStorage is insecure — it's accessible to any JavaScript on the page (XSS) and persists indefinitely. Use httpOnly cookies instead.\",\n check(content, filePath) {\n if (!filePath.match(/\\.(jsx?|tsx?|vue|svelte)$/)) return [];\n if (isTestFile(filePath)) return [];\n // Skip if localStorage.removeItem is used (cleanup code, not storage)\n if (!/localStorage\\.setItem|localStorage\\[/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /localStorage\\.setItem\\s*\\(\\s*[\"'`](?:token|access_token|auth_token|jwt|session|refresh_token|api_key|password|secret)/gi,\n /localStorage\\s*\\[\\s*[\"'`](?:token|access_token|auth_token|jwt|session|refresh_token|api_key|password|secret)/gi,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, sensitiveLocalStorage, filePath, () =>\n \"Don't store tokens/secrets in localStorage — use httpOnly cookies instead. localStorage is accessible to any XSS attack. For session tokens, set them as httpOnly, secure, sameSite cookies.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC055 – Exposed Source Maps in Production\n// ────────────────────────────────────────────\n\nconst exposedSourceMaps: CustomRule = {\n id: \"VC055\",\n title: \"Source Maps Exposed in Production\",\n severity: \"medium\",\n category: \"Information Leakage\",\n description: \"Source map files (.map) in production expose your original source code, comments, and internal logic to anyone who downloads them.\",\n check(content, filePath) {\n // Check build configs for source maps in production\n if (!filePath.match(/(?:webpack|vite|rollup|next)\\.config|tsconfig/i)) return [];\n const matches: RuleMatch[] = [];\n // Source maps enabled without environment check\n if (/(?:sourceMap|source-map|sourcemap)\\s*[:=]\\s*true/i.test(content)) {\n const hasEnvCheck = /process\\.env\\.NODE_ENV|NODE_ENV|production/i.test(content);\n if (!hasEnvCheck) {\n matches.push(...findMatches(content, /(?:sourceMap|source-map|sourcemap)\\s*[:=]\\s*true/gi, exposedSourceMaps, filePath, () =>\n \"Disable source maps in production builds: sourceMap: process.env.NODE_ENV !== 'production'. Or use 'hidden-source-map' to generate maps without exposing them.\"\n ));\n }\n }\n // productionSourceMap in Vue\n if (/productionSourceMap\\s*:\\s*true/i.test(content)) {\n matches.push(...findMatches(content, /productionSourceMap\\s*:\\s*true/gi, exposedSourceMaps, filePath, () =>\n \"Set productionSourceMap: false to avoid exposing source code in production.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC056 – Clickjacking / Missing X-Frame-Options\n// ────────────────────────────────────────────\n\nconst clickjacking: CustomRule = {\n id: \"VC056\",\n title: \"Clickjacking — Missing X-Frame-Options\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Without X-Frame-Options or frame-ancestors CSP directive, your page can be embedded in an attacker's iframe for UI redress (clickjacking) attacks.\",\n check(content, filePath) {\n // Check HTML files\n if (filePath.match(/\\.(html|htm)$/)) {\n if (!/X-Frame-Options|frame-ancestors/i.test(content)) {\n return [{\n rule: \"VC056\", title: clickjacking.title, severity: \"medium\" as const, category: \"Configuration\",\n file: filePath, line: 1, snippet: getSnippet(content, 1),\n fix: 'Add <meta http-equiv=\"X-Frame-Options\" content=\"DENY\"> or set frame-ancestors in CSP to prevent clickjacking.'\n }];\n }\n }\n // Check server configs\n if (/(?:server|app|index|main)\\.[jt]sx?$/.test(filePath)) {\n if (/(?:express|hono|fastify|koa)/i.test(content)) {\n if (!/X-Frame-Options|frame-ancestors|helmet/i.test(content)) {\n return findMatches(content, /(?:express|hono|fastify|koa)\\s*\\(/gi, clickjacking, filePath, () =>\n \"Add X-Frame-Options header: res.setHeader('X-Frame-Options', 'DENY'). Or use helmet: app.use(helmet()) which sets this and other security headers.\"\n );\n }\n }\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC057 – Overly Permissive IAM/Cloud Roles\n// ────────────────────────────────────────────\n\nconst overlyPermissiveIAM: CustomRule = {\n id: \"VC057\",\n title: \"Overly Permissive IAM/Cloud Permissions\",\n severity: \"critical\",\n category: \"Authorization\",\n description: \"Wildcard (*) permissions in AWS IAM, GCP, or Terraform configs grant unrestricted access, violating the principle of least privilege.\",\n check(content, filePath) {\n if (!filePath.match(/\\.(tf|hcl|json|yaml|yml)$/) && !filePath.match(/(?:iam|policy|role|permission)/i)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n // AWS IAM wildcard\n /[\"'`]Action[\"'`]\\s*:\\s*[\"'`]\\*[\"'`]/g,\n /[\"'`]Resource[\"'`]\\s*:\\s*[\"'`]\\*[\"'`]/g,\n // Terraform aws_iam\n /actions\\s*=\\s*\\[\\s*[\"'`]\\*[\"'`]\\s*\\]/g,\n /resources\\s*=\\s*\\[\\s*[\"'`]\\*[\"'`]\\s*\\]/g,\n // GCP bindings\n /role\\s*[:=]\\s*[\"'`]roles\\/(?:owner|editor)[\"'`]/g,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, overlyPermissiveIAM, filePath, () =>\n \"Follow the principle of least privilege: replace wildcard (*) with specific actions and resources. Example: 'Action': 's3:GetObject' instead of '*'.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC058 – Docker Running as Root\n// ────────────────────────────────────────────\n\nconst dockerRunAsRoot: CustomRule = {\n id: \"VC058\",\n title: \"Docker Container Running as Root\",\n severity: \"high\",\n category: \"Configuration\",\n description: \"Containers running as root give attackers full system access if they escape the container. Always run as a non-root user.\",\n check(content, filePath) {\n if (!filePath.match(/Dockerfile$/i)) return [];\n const hasUser = /^\\s*USER\\s+/m.test(content);\n if (hasUser) return [];\n return [{\n rule: \"VC058\", title: dockerRunAsRoot.title, severity: \"high\" as const, category: \"Configuration\",\n file: filePath, line: 1, snippet: getSnippet(content, 1),\n fix: \"Add a USER directive: RUN addgroup -S app && adduser -S app -G app\\\\nUSER app. Place it after installing dependencies but before COPY/CMD.\"\n }];\n },\n};\n\n// ────────────────────────────────────────────\n// VC059 – Exposed Ports in Docker Compose\n// ────────────────────────────────────────────\n\nconst exposedDockerPorts: CustomRule = {\n id: \"VC059\",\n title: \"Docker Compose Binding to All Interfaces\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Binding ports to 0.0.0.0 (default) in Docker Compose exposes services to the entire network. Bind to 127.0.0.1 for local-only access.\",\n check(content, filePath) {\n if (!filePath.match(/docker-compose|compose\\.(yaml|yml)$/i)) return [];\n const matches: RuleMatch[] = [];\n // ports: \"3000:3000\" or \"8080:80\" without binding to 127.0.0.1\n const portPattern = /ports:\\s*\\n(?:\\s*-\\s*[\"'`]?\\d+:\\d+[\"'`]?\\s*\\n?)+/g;\n if (portPattern.test(content) && !/127\\.0\\.0\\.1:/i.test(content)) {\n matches.push(...findMatches(content, /^\\s*-\\s*[\"'`]?\\d+:\\d+[\"'`]?/gm, exposedDockerPorts, filePath, () =>\n \"Bind to localhost only: '127.0.0.1:3000:3000' instead of '3000:3000'. This prevents external network access to the service.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC060 – Weak Hashing Algorithm\n// ────────────────────────────────────────────\n\nconst weakHashing: CustomRule = {\n id: \"VC060\",\n title: \"Weak Hashing Algorithm for Passwords\",\n severity: \"critical\",\n category: \"Cryptography\",\n description: \"MD5 and SHA1/SHA256 are too fast for password hashing — they can be brute-forced at billions of attempts per second. Use bcrypt, scrypt, or argon2 instead.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n // Skip if file also uses strong hashing (indicates migration or comparison code)\n if (/bcrypt|scrypt|argon2/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n // MD5/SHA used with password context\n const patterns = [\n /(?:md5|sha1|sha256|sha512)\\s*\\([^)]*(?:password|passwd|pwd)/gi,\n /createHash\\s*\\(\\s*[\"'`](?:md5|sha1|sha256)[\"'`]\\).*(?:password|passwd|pwd)/gi,\n /(?:password|passwd|pwd).*createHash\\s*\\(\\s*[\"'`](?:md5|sha1|sha256)[\"'`]\\)/gi,\n /hashlib\\.(?:md5|sha1|sha256)\\s*\\([^)]*(?:password|passwd|pwd)/gi,\n /Digest::(?:MD5|SHA1|SHA256).*(?:password|passwd|pwd)/gi,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, weakHashing, filePath, () =>\n \"Use bcrypt, scrypt, or argon2 for password hashing — they're intentionally slow. Example: const hash = await bcrypt.hash(password, 12);\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC061 – Disabled TLS Certificate Verification\n// ────────────────────────────────────────────\n\nconst disabledTLSVerification: CustomRule = {\n id: \"VC061\",\n title: \"Disabled TLS Certificate Verification\",\n severity: \"critical\",\n category: \"Cryptography\",\n description: \"Disabling TLS certificate verification (NODE_TLS_REJECT_UNAUTHORIZED=0 or rejectUnauthorized:false) makes all HTTPS connections vulnerable to man-in-the-middle attacks.\",\n check(content, filePath) {\n const matches: RuleMatch[] = [];\n const patterns = [\n /NODE_TLS_REJECT_UNAUTHORIZED\\s*[:=]\\s*[\"'`]?0[\"'`]?/g,\n /rejectUnauthorized\\s*:\\s*false/g,\n /verify\\s*[:=]\\s*false.*(?:ssl|tls|cert|https)/gi,\n /PYTHONHTTPSVERIFY\\s*[:=]\\s*[\"'`]?0[\"'`]?/g,\n /ssl_verify\\s*[:=]\\s*false/gi,\n /InsecureSkipVerify\\s*:\\s*true/g,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, disabledTLSVerification, filePath, () =>\n \"Never disable TLS certificate verification in production. Fix the root cause: install the correct CA certificate, or use NODE_EXTRA_CA_CERTS for custom CAs.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC062 – Hardcoded Encryption Key/IV\n// ────────────────────────────────────────────\n\nconst hardcodedEncryptionKey: CustomRule = {\n id: \"VC062\",\n title: \"Hardcoded Encryption Key or IV\",\n severity: \"critical\",\n category: \"Cryptography\",\n description: \"Hardcoded encryption keys and initialization vectors (IVs) in source code can be extracted to decrypt all data. IVs must be random per encryption operation.\",\n check(content, filePath) {\n if (filePath.endsWith(\".example\") || filePath.endsWith(\".template\")) return [];\n if (isTestFile(filePath)) return [];\n // Skip HTML/XML/config files — meta tags and config values are not encryption keys\n if (filePath.match(/\\.(html|htm|xml|plist|svg|xhtml)$/)) return [];\n // Skip files without any crypto-related code\n if (!/(?:cipher|encrypt|decrypt|crypto|aes|createCipher)/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n // Encryption key as string literal\n /(?:encryption_key|encryptionKey|cipher_key|cipherKey|aes_key|AES_KEY|ENCRYPTION_KEY)\\s*[:=]\\s*[\"'`][^\"'`]{8,}[\"'`]/g,\n // createCipheriv with hardcoded key\n /createCipher(?:iv)?\\s*\\(\\s*[\"'`][^\"'`]+[\"'`]\\s*,\\s*[\"'`][^\"'`]+[\"'`]/g,\n // Buffer.from with hardcoded key near cipher context\n /(?:key|iv|nonce)\\s*[:=]\\s*Buffer\\.from\\s*\\(\\s*[\"'`][^\"'`]{8,}[\"'`]/gi,\n // Static IV (should be random) — only in crypto context\n /(?:^|[\\s,({])(?:iv|nonce|initialVector)\\s*[:=]\\s*[\"'`][0-9a-fA-F]{16,}[\"'`]/gi,\n ];\n for (const p of patterns) {\n const rawMatches = findMatches(content, p, hardcodedEncryptionKey, filePath, () =>\n \"Move encryption keys to environment variables. Generate IVs randomly per operation: crypto.randomBytes(16). Never reuse IVs.\"\n );\n // Skip matches on lines containing CSP meta tags or security headers\n for (const rm of rawMatches) {\n const lineStart = content.lastIndexOf(\"\\n\", content.split(\"\\n\").slice(0, rm.line - 1).join(\"\\n\").length) + 1;\n const lineEnd = content.indexOf(\"\\n\", lineStart + 1);\n const lineText = content.substring(lineStart, lineEnd === -1 ? content.length : lineEnd);\n if (/meta\\s+http-equiv|Content-Security-Policy|X-Frame-Options|X-Content-Type/i.test(lineText)) continue;\n matches.push(rm);\n }\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC063 – dangerouslySetInnerHTML\n// ────────────────────────────────────────────\n\nconst dangerousInnerHTML: CustomRule = {\n id: \"VC063\",\n title: \"Unsanitized dangerouslySetInnerHTML\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"Using dangerouslySetInnerHTML without sanitization (DOMPurify) enables XSS attacks. User-controlled content injected as raw HTML can execute arbitrary JavaScript.\",\n check(content, filePath) {\n if (!filePath.match(/\\.(jsx|tsx)$/)) return [];\n if (!/dangerouslySetInnerHTML/i.test(content)) return [];\n const hasSanitize = /DOMPurify|sanitize|purify|xss|sanitizeHtml|isomorphic-dompurify/i.test(content);\n if (hasSanitize) return [];\n return findMatches(content, /dangerouslySetInnerHTML\\s*=\\s*\\{\\s*\\{/g, dangerousInnerHTML, filePath, () =>\n \"Sanitize HTML before using dangerouslySetInnerHTML: dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(content) }}. Install: npm install dompurify\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC064 – Exposed Next.js Server Actions\n// ────────────────────────────────────────────\n\nconst exposedServerActions: CustomRule = {\n id: \"VC064\",\n title: \"Next.js Server Action Without Auth Check\",\n severity: \"high\",\n category: \"Authorization\",\n description: \"Next.js Server Actions ('use server') are publicly callable endpoints. Without authentication checks, anyone can invoke them directly.\",\n check(content, filePath) {\n if (!filePath.match(/\\.(jsx?|tsx?)$/)) return [];\n if (!/[\"']use server[\"']/i.test(content)) return [];\n const hasAuth = /getServerSession|auth\\(\\)|currentUser|getUser|requireAuth|session|clerk|getAuth/i.test(content);\n if (hasAuth) return [];\n // Check if there are exported async functions (server actions)\n if (/export\\s+async\\s+function/i.test(content)) {\n return findMatches(content, /export\\s+async\\s+function\\s+\\w+/g, exposedServerActions, filePath, () =>\n \"Add authentication to Server Actions: const session = await getServerSession(); if (!session) throw new Error('Unauthorized');\"\n );\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC065 – Unprotected Next.js API Routes\n// ────────────────────────────────────────────\n\nconst unprotectedAPIRoutes: CustomRule = {\n id: \"VC065\",\n title: \"Unprotected Next.js API Route\",\n severity: \"high\",\n category: \"Authorization\",\n description: \"Next.js API routes under /api/ without authentication middleware can be called by anyone, exposing data or mutations.\",\n check(content, filePath) {\n if (!filePath.match(/\\/api\\/.*\\.(jsx?|tsx?)$/) && !filePath.match(/\\/app\\/api\\/.*route\\.(jsx?|tsx?)$/)) return [];\n // Skip health/public endpoints\n if (/health|status|public|webhook/i.test(filePath)) return [];\n const hasAuth = /getServerSession|auth\\(\\)|currentUser|getUser|requireAuth|session|clerk|getAuth|verifyToken|authenticate|middleware/i.test(content);\n if (hasAuth) return [];\n const hasHandler = /export\\s+(?:async\\s+)?function\\s+(?:GET|POST|PUT|DELETE|PATCH)|export\\s+default/i.test(content);\n if (hasHandler) {\n return findMatches(content, /export\\s+(?:async\\s+)?function\\s+(?:GET|POST|PUT|DELETE|PATCH)/g, unprotectedAPIRoutes, filePath, () =>\n \"Add authentication to API routes: const session = await getServerSession(authOptions); if (!session) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\"\n );\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC066 – Client Component Using Secrets\n// ────────────────────────────────────────────\n\nconst clientComponentSecret: CustomRule = {\n id: \"VC066\",\n title: \"Secret Used in Client Component\",\n severity: \"critical\",\n category: \"Secrets\",\n description: \"Using server-side secrets (process.env without NEXT_PUBLIC_) in 'use client' components exposes them in the browser bundle.\",\n check(content, filePath) {\n if (!filePath.match(/\\.(jsx?|tsx?)$/)) return [];\n if (!/[\"']use client[\"']/i.test(content)) return [];\n // process.env without NEXT_PUBLIC_ prefix in a client component\n const pattern = /process\\.env\\.(?!NEXT_PUBLIC_)[A-Z_]{3,}/g;\n if (pattern.test(content)) {\n return findMatches(content, /process\\.env\\.(?!NEXT_PUBLIC_)[A-Z_]{3,}/g, clientComponentSecret, filePath, () =>\n \"Server-side env vars are not available in client components and may leak in builds. Move this logic to a Server Component or API route.\"\n );\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC067 – Insecure Deep Link Handling\n// ────────────────────────────────────────────\n\nconst insecureDeepLink: CustomRule = {\n id: \"VC067\",\n title: \"Insecure Deep Link Handling\",\n severity: \"high\",\n category: \"Injection\",\n description: \"Deep links that navigate or execute actions without validating the URL scheme, host, or parameters can be exploited for phishing or unauthorized actions.\",\n check(content, filePath) {\n if (!/(?:Linking|DeepLinking|deep.?link|handleURL|openURL|url.?scheme)/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n // React Native Linking without validation\n const patterns = [\n /Linking\\.addEventListener\\s*\\([^)]*(?:url|link)/gi,\n /Linking\\.getInitialURL\\s*\\(\\)/g,\n /handleOpenURL|handleDeepLink|onDeepLink/gi,\n ];\n const hasValidation = /allowedSchemes|allowedHosts|validateURL|isAllowedURL|whitelist|URL.*hostname.*includes/i.test(content);\n if (hasValidation) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, insecureDeepLink, filePath, () =>\n \"Validate deep link URLs: check the scheme and host against an allowlist before navigating or executing actions.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC068 – Sensitive Data in AsyncStorage\n// ────────────────────────────────────────────\n\nconst sensitiveAsyncStorage: CustomRule = {\n id: \"VC068\",\n title: \"Sensitive Data in AsyncStorage\",\n severity: \"high\",\n category: \"Secrets\",\n description: \"React Native AsyncStorage is unencrypted. Storing tokens, passwords, or secrets there makes them readable by other apps or anyone with device access.\",\n check(content, filePath) {\n if (!/AsyncStorage/i.test(content)) return [];\n const patterns = [\n /AsyncStorage\\.setItem\\s*\\(\\s*[\"'`](?:token|access_token|auth_token|jwt|session|refresh_token|api_key|password|secret|private_key)/gi,\n ];\n const matches: RuleMatch[] = [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, sensitiveAsyncStorage, filePath, () =>\n \"Use react-native-keychain or expo-secure-store instead of AsyncStorage for sensitive data. These use the OS keychain (encrypted).\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC069 – Missing Certificate Pinning\n// ────────────────────────────────────────────\n\nconst missingCertPinning: CustomRule = {\n id: \"VC069\",\n title: \"Missing Certificate Pinning in Mobile App\",\n severity: \"medium\",\n category: \"Cryptography\",\n description: \"Mobile apps without SSL certificate pinning are vulnerable to MITM attacks via compromised or rogue CAs. Pin your API server's certificate.\",\n check(content, filePath) {\n // Only for mobile project files\n if (!/(?:react.native|expo|android|ios|mobile)/i.test(filePath) && !/(?:React.*Native|expo)/i.test(content)) return [];\n if (!/(?:fetch|axios|http|api|request)/i.test(content)) return [];\n // Check for HTTP client setup without pinning\n if (/axios\\.create|new\\s+(?:HttpClient|ApiClient)/i.test(content)) {\n const hasPinning = /pinning|certificate|cert|ssl|TrustKit|react-native-ssl-pinning|cert-pinner/i.test(content);\n if (!hasPinning) {\n return findMatches(content, /axios\\.create|new\\s+(?:HttpClient|ApiClient)/gi, missingCertPinning, filePath, () =>\n \"Add SSL certificate pinning: use react-native-ssl-pinning or TrustKit. This prevents MITM attacks via rogue certificates.\"\n );\n }\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC070 – Android Debuggable Flag\n// ────────────────────────────────────────────\n\nconst androidDebuggable: CustomRule = {\n id: \"VC070\",\n title: \"Android App Debuggable in Production\",\n severity: \"high\",\n category: \"Configuration\",\n description: \"android:debuggable='true' in AndroidManifest.xml allows attackers to attach debuggers, inspect memory, and bypass security controls.\",\n check(content, filePath) {\n if (!filePath.match(/AndroidManifest\\.xml$/i)) return [];\n if (/android:debuggable\\s*=\\s*[\"']true[\"']/i.test(content)) {\n return findMatches(content, /android:debuggable\\s*=\\s*[\"']true[\"']/gi, androidDebuggable, filePath, () =>\n \"Remove android:debuggable='true' or set it to false. Debug builds should use build variants, not manifest flags.\"\n );\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC071 – Django DEBUG=True\n// ────────────────────────────────────────────\n\nconst djangoDebug: CustomRule = {\n id: \"VC071\",\n title: \"Django DEBUG Mode Enabled\",\n severity: \"critical\",\n category: \"Configuration\",\n description: \"Django with DEBUG=True exposes detailed error pages with source code, database queries, environment variables, and installed apps to anyone.\",\n check(content, filePath) {\n if (!filePath.match(/settings\\.py$/i) && !filePath.match(/config.*\\.py$/i)) return [];\n if (/^\\s*DEBUG\\s*=\\s*True\\s*$/m.test(content)) {\n const hasEnvCheck = /os\\.environ|env\\(|config\\(|getenv/i.test(content);\n if (!hasEnvCheck) {\n return findMatches(content, /^\\s*DEBUG\\s*=\\s*True/gm, djangoDebug, filePath, () =>\n \"Use environment variable: DEBUG = os.environ.get('DEBUG', 'False') == 'True'. Never hardcode DEBUG=True.\"\n );\n }\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC072 – Flask Hardcoded Secret Key\n// ────────────────────────────────────────────\n\nconst flaskSecretKey: CustomRule = {\n id: \"VC072\",\n title: \"Flask Secret Key Hardcoded\",\n severity: \"critical\",\n category: \"Secrets\",\n description: \"Hardcoded Flask secret_key allows attackers to forge sessions, CSRF tokens, and signed cookies. Must be a random value from environment variables.\",\n check(content, filePath) {\n if (!filePath.match(/\\.py$/)) return [];\n const patterns = [\n /(?:app\\.)?secret_key\\s*=\\s*[\"'`][^\"'`]{3,}[\"'`]/g,\n /(?:app\\.config)\\s*\\[\\s*[\"']SECRET_KEY[\"']\\s*\\]\\s*=\\s*[\"'`][^\"'`]{3,}[\"'`]/g,\n ];\n const hasEnv = /os\\.environ|env\\(|config\\(|getenv/i.test(content);\n if (hasEnv) return [];\n const matches: RuleMatch[] = [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, flaskSecretKey, filePath, () =>\n \"Use environment variable: app.secret_key = os.environ['SECRET_KEY']. Generate with: python -c \\\"import secrets; print(secrets.token_hex(32))\\\"\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC073 – Pickle Deserialization\n// ────────────────────────────────────────────\n\nconst pickleDeserialization: CustomRule = {\n id: \"VC073\",\n title: \"Unsafe Pickle Deserialization\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"pickle.loads() on untrusted data allows arbitrary code execution. An attacker can craft a pickle payload that runs system commands on your server.\",\n check(content, filePath) {\n if (!filePath.match(/\\.py$/)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /pickle\\.loads?\\s*\\(/g,\n /cPickle\\.loads?\\s*\\(/g,\n /shelve\\.open\\s*\\(/g,\n /yaml\\.load\\s*\\([^)]*(?!Loader\\s*=\\s*yaml\\.SafeLoader)/g,\n ];\n const hasSafe = /restricted_loads|SafeUnpickler|safe_load|yaml\\.safe_load/i.test(content);\n if (hasSafe) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, pickleDeserialization, filePath, () =>\n \"Never unpickle untrusted data — it allows arbitrary code execution. Use JSON for data exchange, or yaml.safe_load() for YAML.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC074 – Missing CSRF Protection (Django)\n// ────────────────────────────────────────────\n\nconst missingCSRF: CustomRule = {\n id: \"VC074\",\n title: \"CSRF Protection Disabled\",\n severity: \"high\",\n category: \"Authorization\",\n description: \"Using @csrf_exempt on state-changing views (POST/PUT/DELETE) allows attackers to forge requests from other sites, performing actions as authenticated users.\",\n check(content, filePath) {\n if (!filePath.match(/\\.py$/)) return [];\n const matches: RuleMatch[] = [];\n if (/csrf_exempt/i.test(content)) {\n matches.push(...findMatches(content, /@csrf_exempt/g, missingCSRF, filePath, () =>\n \"Remove @csrf_exempt and use proper CSRF tokens. For APIs, use token-based auth (JWT) instead of session cookies.\"\n ));\n }\n // Also check for CsrfViewMiddleware removal\n if (/MIDDLEWARE.*=.*\\[/s.test(content) && !/CsrfViewMiddleware/i.test(content) && /django/i.test(content)) {\n matches.push(...findMatches(content, /MIDDLEWARE\\s*=/g, missingCSRF, filePath, () =>\n \"Re-add 'django.middleware.csrf.CsrfViewMiddleware' to MIDDLEWARE. CSRF protection is essential for session-based auth.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC075 – GitHub Actions Script Injection\n// ────────────────────────────────────────────\n\nconst githubActionsInjection: CustomRule = {\n id: \"VC075\",\n title: \"GitHub Actions Script Injection\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"Using ${{ github.event.* }} directly in 'run:' steps allows attackers to inject shell commands via PR titles, issue bodies, or branch names.\",\n check(content, filePath) {\n if (!filePath.match(/\\.github\\/workflows\\/.*\\.(yml|yaml)$/i)) return [];\n const matches: RuleMatch[] = [];\n // Direct interpolation in run steps\n const patterns = [\n /run:.*\\$\\{\\{\\s*github\\.event\\.(?:issue|pull_request|comment|review|head_commit)\\.(?:title|body|message)/gi,\n /run:.*\\$\\{\\{\\s*github\\.event\\.(?:inputs|head_ref|base_ref)/gi,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, githubActionsInjection, filePath, () =>\n \"Never use ${{ github.event.* }} directly in 'run:'. Pass it as an environment variable: env: TITLE: ${{ github.event.issue.title }} then use $TITLE in the script.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC076 – Secrets in CI Config\n// ────────────────────────────────────────────\n\nconst secretsInCI: CustomRule = {\n id: \"VC076\",\n title: \"Hardcoded Secrets in CI/CD Config\",\n severity: \"critical\",\n category: \"Secrets\",\n description: \"Hardcoded tokens, passwords, or API keys in CI/CD workflow files are visible to anyone with repo access. Use encrypted secrets instead.\",\n check(content, filePath) {\n if (!filePath.match(/\\.github\\/workflows\\/|\\.gitlab-ci|Jenkinsfile|\\.circleci|bitbucket-pipelines/i)) return [];\n const matches: RuleMatch[] = [];\n // Hardcoded values that look like secrets (not using ${{ secrets.* }})\n const patterns = [\n /(?:password|token|key|secret|api_key|apikey)\\s*[:=]\\s*[\"'`][A-Za-z0-9+/=_-]{20,}[\"'`]/gi,\n /(?:DOCKER_PASSWORD|NPM_TOKEN|AWS_SECRET_ACCESS_KEY|GH_TOKEN|GITHUB_TOKEN)\\s*[:=]\\s*[\"'`][^\"'`$]+[\"'`]/gi,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, secretsInCI, filePath, () =>\n \"Use repository secrets: ${{ secrets.MY_TOKEN }} (GitHub) or CI/CD variable settings. Never hardcode credentials in workflow files.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC077 – CORS Wildcard in Serverless Config\n// ────────────────────────────────────────────\n\nconst corsServerless: CustomRule = {\n id: \"VC077\",\n title: \"CORS Wildcard in Serverless Config\",\n severity: \"high\",\n category: \"Configuration\",\n description: \"Setting Access-Control-Allow-Origin: * in serverless.yml, vercel.json, or similar configs allows any website to make authenticated requests to your API.\",\n check(content, filePath) {\n if (!filePath.match(/serverless\\.(yml|yaml)|vercel\\.json|netlify\\.toml|amplify\\.yml/i)) return [];\n const matches: RuleMatch[] = [];\n if (/(?:Access-Control-Allow-Origin|allowOrigin|cors).*['\"]\\*['\"]/i.test(content)) {\n matches.push(...findMatches(content, /(?:Access-Control-Allow-Origin|allowOrigin|cors).*['\"]\\*['\"]/gi, corsServerless, filePath, () =>\n \"Replace wildcard CORS with specific origins: allowOrigin: ['https://yourdomain.com']. Wildcard allows any site to call your API.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC078 – Kubernetes Privileged Container\n// ────────────────────────────────────────────\n\nconst k8sPrivileged: CustomRule = {\n id: \"VC078\",\n title: \"Kubernetes Privileged Container\",\n severity: \"critical\",\n category: \"Configuration\",\n description: \"Running containers with privileged: true or as root in Kubernetes gives full host access, making container escapes trivial.\",\n check(content, filePath) {\n if (!filePath.match(/\\.(yaml|yml)$/) || !/(?:kind|apiVersion|container)/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /privileged\\s*:\\s*true/g,\n /runAsUser\\s*:\\s*0\\b/g,\n /runAsNonRoot\\s*:\\s*false/g,\n /allowPrivilegeEscalation\\s*:\\s*true/g,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, k8sPrivileged, filePath, () =>\n \"Set securityContext: { privileged: false, runAsNonRoot: true, allowPrivilegeEscalation: false }. Never run containers as root in production.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// FRAMEWORK DETECTION\n// ────────────────────────────────────────────\n\nexport type DetectedFramework = \"next.js\" | \"react\" | \"react-native\" | \"express\" | \"hono\" | \"fastify\" | \"django\" | \"flask\" | \"electron\" | \"vue\" | \"svelte\" | \"unknown\";\n\nexport function detectFramework(files: { path: string; content: string }[]): DetectedFramework[] {\n const frameworks: Set<DetectedFramework> = new Set();\n for (const { path, content } of files) {\n if (path.match(/next\\.config/i) || /from\\s+[\"']next/i.test(content)) frameworks.add(\"next.js\");\n if (/from\\s+[\"']react-native/i.test(content) || path.match(/react-native\\.config/i)) frameworks.add(\"react-native\");\n else if (/from\\s+[\"']react/i.test(content) || /import\\s+React/i.test(content)) frameworks.add(\"react\");\n if (/from\\s+[\"']express/i.test(content) || /require\\s*\\(\\s*[\"']express/i.test(content)) frameworks.add(\"express\");\n if (/from\\s+[\"']hono/i.test(content)) frameworks.add(\"hono\");\n if (/from\\s+[\"']fastify/i.test(content)) frameworks.add(\"fastify\");\n if (/from\\s+[\"']electron/i.test(content) || path.match(/electron/i)) frameworks.add(\"electron\");\n if (path.match(/settings\\.py$/) || /from\\s+django/i.test(content)) frameworks.add(\"django\");\n if (/from\\s+flask/i.test(content) || /Flask\\s*\\(/i.test(content)) frameworks.add(\"flask\");\n if (/from\\s+[\"']vue/i.test(content) || path.match(/vue\\.config/i)) frameworks.add(\"vue\");\n if (/from\\s+[\"']svelte/i.test(content) || path.match(/svelte\\.config/i)) frameworks.add(\"svelte\");\n }\n if (frameworks.size === 0) frameworks.add(\"unknown\");\n return [...frameworks];\n}\n\n// ────────────────────────────────────────────\n// SEVERITY GRADING\n// ────────────────────────────────────────────\n\nexport type SecurityGrade = \"A+\" | \"A\" | \"B\" | \"C\" | \"D\" | \"F\";\n\nexport interface GradeResult {\n grade: SecurityGrade;\n score: number;\n summary: string;\n}\n\nexport function calculateGrade(findings: Finding[], totalFiles: number): GradeResult {\n if (findings.length === 0) {\n return { grade: \"A+\", score: 100, summary: \"No security issues detected. Excellent!\" };\n }\n\n // Weight by severity\n let deductions = 0;\n for (const f of findings) {\n switch (f.severity) {\n case \"critical\": deductions += 15; break;\n case \"high\": deductions += 8; break;\n case \"medium\": deductions += 4; break;\n case \"low\": deductions += 1; break;\n }\n }\n\n // Scale relative to project size (larger projects get a slight buffer)\n const sizeBuffer = Math.min(Math.log2(Math.max(totalFiles, 1)) * 2, 15);\n const score = Math.max(0, Math.min(100, 100 - deductions + sizeBuffer));\n\n let grade: SecurityGrade;\n let summary: string;\n\n if (score >= 95) { grade = \"A+\"; summary = \"Excellent security posture with minimal issues.\"; }\n else if (score >= 85) { grade = \"A\"; summary = \"Strong security with a few minor concerns.\"; }\n else if (score >= 70) { grade = \"B\"; summary = \"Good security but some issues need attention.\"; }\n else if (score >= 55) { grade = \"C\"; summary = \"Fair security — several vulnerabilities should be fixed.\"; }\n else if (score >= 35) { grade = \"D\"; summary = \"Poor security — critical issues require immediate attention.\"; }\n else { grade = \"F\"; summary = \"Failing — serious vulnerabilities present. Fix critical issues immediately.\"; }\n\n return { grade, score: Math.round(score), summary };\n}\n\n// ────────────────────────────────────────────\n// VC079 – JWT Algorithm Confusion\n// ────────────────────────────────────────────\n\nconst jwtAlgConfusion: CustomRule = {\n id: \"VC079\",\n title: \"JWT Algorithm Confusion (alg:none)\",\n severity: \"critical\",\n category: \"Authentication\",\n description: \"Accepting 'none' as a JWT algorithm allows attackers to forge tokens by removing the signature entirely.\",\n check(content, filePath) {\n if (!/jwt|jsonwebtoken|jose/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /algorithms\\s*:\\s*\\[.*[\"']none[\"']/gi,\n /algorithm\\s*[:=]\\s*[\"']none[\"']/gi,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, jwtAlgConfusion, filePath, () =>\n \"Never allow algorithm 'none'. Explicitly specify: algorithms: ['RS256'] or algorithms: ['HS256']. Reject tokens with alg:none.\"\n ));\n }\n // Also check for missing algorithm restriction\n if (/jwt\\.verify\\s*\\([^)]*\\)\\s*(?!.*algorithms)/i.test(content) && !/algorithms/i.test(content)) {\n matches.push(...findMatches(content, /jwt\\.verify\\s*\\(/g, jwtAlgConfusion, filePath, () =>\n \"Specify allowed algorithms in jwt.verify: jwt.verify(token, secret, { algorithms: ['HS256'] }).\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC080 – Regex DoS (ReDoS)\n// ────────────────────────────────────────────\n\nconst regexDos: CustomRule = {\n id: \"VC080\",\n title: \"Potential Regular Expression DoS (ReDoS)\",\n severity: \"high\",\n category: \"Availability\",\n description: \"Nested quantifiers like (a+)+ or (a*){2,} cause catastrophic backtracking, allowing attackers to freeze your server with crafted input.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n const matches: RuleMatch[] = [];\n // Detect nested quantifiers in regex\n const patterns = [\n /new\\s+RegExp\\s*\\(\\s*[\"'`].*\\([^)]*[+*]\\)[+*{]/g,\n /\\/.*\\([^)]*[+*]\\)[+*{].*\\//g,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, regexDos, filePath, () =>\n \"Avoid nested quantifiers in regex. Use atomic groups, possessive quantifiers, or the 're2' library for safe regex execution.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC081 – XML External Entity (XXE)\n// ────────────────────────────────────────────\n\nconst xxeVulnerability: CustomRule = {\n id: \"VC081\",\n title: \"XML External Entity (XXE) Injection\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"XML parsers that process external entities allow attackers to read files, perform SSRF, or cause DoS via billion-laughs attacks.\",\n check(content, filePath) {\n if (!/xml|parseXML|DOMParser|SAXParser|etree|lxml/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /\\.parseXML\\s*\\(/g,\n /new\\s+DOMParser\\s*\\(\\)/g,\n /etree\\.parse\\s*\\(/g,\n /lxml\\.etree/g,\n /SAXParserFactory/g,\n /XMLReaderFactory/g,\n ];\n const hasProtection = /noent.*false|resolveExternals.*false|FEATURE_EXTERNAL.*false|defusedxml|disallow-doctype-decl/i.test(content);\n if (hasProtection) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, xxeVulnerability, filePath, () =>\n \"Disable external entities: set noent: false, or use defusedxml (Python). For Java: factory.setFeature('http://apache.org/xml/features/disallow-doctype-decl', true).\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC082 – Server-Side Template Injection\n// ────────────────────────────────────────────\n\nconst ssti: CustomRule = {\n id: \"VC082\",\n title: \"Server-Side Template Injection (SSTI)\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"Rendering templates from user-controlled strings allows attackers to execute arbitrary code on the server.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /render_template_string\\s*\\(\\s*(?![\"'`])/g,\n /Template\\s*\\(\\s*(?:req\\.|body\\.|input|params|args|user)/gi,\n /engine\\.render\\s*\\(\\s*(?:req\\.|body\\.|input)/gi,\n /nunjucks\\.renderString\\s*\\(\\s*(?:req\\.|body\\.|input)/gi,\n /ejs\\.render\\s*\\(\\s*(?:req\\.|body\\.|input)/gi,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, ssti, filePath, () =>\n \"Never render templates from user input. Use pre-defined templates and pass data as context variables: render_template('template.html', data=user_data).\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC083 – Insecure Java Deserialization\n// ────────────────────────────────────────────\n\nconst javaDeserialization: CustomRule = {\n id: \"VC083\",\n title: \"Insecure Java Deserialization\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"ObjectInputStream.readObject() on untrusted data allows arbitrary code execution via gadget chains in the classpath.\",\n check(content, filePath) {\n if (!filePath.match(/\\.java$|\\.kt$/)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /ObjectInputStream\\s*\\(/g,\n /\\.readObject\\s*\\(\\)/g,\n /XMLDecoder\\s*\\(/g,\n /XStream\\s*\\(\\)/g,\n ];\n const hasSafe = /ValidatingObjectInputStream|ObjectInputFilter|SerialKiller|NotSerializableException/i.test(content);\n if (hasSafe) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, javaDeserialization, filePath, () =>\n \"Use ValidatingObjectInputStream with an allowlist of classes, or avoid Java serialization entirely. Use JSON instead.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC084 – Missing Subresource Integrity (SRI)\n// ────────────────────────────────────────────\n\nconst missingSRI: CustomRule = {\n id: \"VC084\",\n title: \"Missing Subresource Integrity (SRI)\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"External scripts and stylesheets loaded without integrity= attributes can be tampered with if the CDN is compromised.\",\n check(content, filePath) {\n if (!filePath.match(/\\.(html|htm|jsx|tsx|ejs|hbs)$/)) return [];\n const matches: RuleMatch[] = [];\n // Script tags with external src but no integrity\n const scriptPattern = /<script\\s+[^>]*src\\s*=\\s*[\"']https?:\\/\\/[^\"']+[\"'][^>]*>/gi;\n let m: RegExpExecArray | null;\n const re = new RegExp(scriptPattern.source, scriptPattern.flags);\n while ((m = re.exec(content)) !== null) {\n if (!m[0].includes(\"integrity\")) {\n const lineNum = content.substring(0, m.index).split(\"\\n\").length;\n matches.push({\n rule: \"VC084\", title: missingSRI.title, severity: \"medium\", category: \"Configuration\",\n file: filePath, line: lineNum, snippet: getSnippet(content, lineNum),\n fix: 'Add integrity and crossorigin attributes: <script src=\"...\" integrity=\"sha384-...\" crossorigin=\"anonymous\">'\n });\n }\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC085 – Exposed Admin/Debug Routes\n// ────────────────────────────────────────────\n\nconst exposedAdminRoutes: CustomRule = {\n id: \"VC085\",\n title: \"Exposed Admin or Debug Route\",\n severity: \"high\",\n category: \"Information Leakage\",\n description: \"Routes like /admin, /debug, /phpinfo, or /actuator without authentication expose sensitive controls and information to attackers.\",\n check(content, filePath) {\n if (!/(?:\\/api\\/|routes?\\/|server\\.|app\\.|index\\.[jt]s)/i.test(filePath)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /[.'\"]\\s*(?:get|use|all)\\s*\\(\\s*[\"'`]\\/(?:admin|debug|_debug|__debug__|phpinfo|actuator|graphiql|playground|swagger)[\"'`]/gi,\n ];\n const hasAuth = /auth|requireAuth|isAdmin|requireAdmin|authenticate|middleware.*admin/i.test(content);\n if (hasAuth) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, exposedAdminRoutes, filePath, () =>\n \"Protect admin/debug routes with authentication middleware. In production, disable debug endpoints entirely.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC086 – Insecure WebSocket\n// ────────────────────────────────────────────\n\nconst insecureWebSocket: CustomRule = {\n id: \"VC086\",\n title: \"Insecure WebSocket Connection (ws://)\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Using ws:// instead of wss:// transmits data in plaintext, vulnerable to eavesdropping and man-in-the-middle attacks.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n return findMatches(content, /new\\s+WebSocket\\s*\\(\\s*[\"'`]ws:\\/\\//g, insecureWebSocket, filePath, () =>\n \"Use wss:// (WebSocket Secure) instead of ws:// for encrypted connections: new WebSocket('wss://...').\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC087 – Missing HSTS\n// ────────────────────────────────────────────\n\nconst missingHSTS: CustomRule = {\n id: \"VC087\",\n title: \"Missing HTTP Strict Transport Security (HSTS)\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Without HSTS headers, browsers allow downgrade attacks from HTTPS to HTTP, exposing traffic to interception.\",\n check(content, filePath) {\n if (!/(?:server|app|index|main)\\.[jt]sx?$/.test(filePath)) return [];\n if (!/(?:express|hono|fastify|koa)/i.test(content)) return [];\n if (/Strict-Transport-Security|hsts|helmet/i.test(content)) return [];\n return findMatches(content, /(?:express|hono|fastify|koa)\\s*\\(/gi, missingHSTS, filePath, () =>\n \"Add HSTS header: res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains'). Or use helmet().\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC088 – Sensitive Data in URL Parameters\n// ────────────────────────────────────────────\n\nconst sensitiveURLParams: CustomRule = {\n id: \"VC088\",\n title: \"Sensitive Data in URL Parameters\",\n severity: \"high\",\n category: \"Information Leakage\",\n description: \"Passing passwords, tokens, or API keys in URL query parameters exposes them in server logs, browser history, and referrer headers.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /\\?\\s*(?:password|token|secret|api_key|apiKey|access_token|ssn|credit_card)\\s*=/gi,\n /[&?](?:password|token|secret|api_key|apiKey|access_token)\\s*=\\s*\\$\\{/gi,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, sensitiveURLParams, filePath, () =>\n \"Never pass sensitive data in URL parameters. Use request headers (Authorization: Bearer ...) or POST body instead.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC089 – Missing Content-Disposition\n// ────────────────────────────────────────────\n\nconst missingContentDisposition: CustomRule = {\n id: \"VC089\",\n title: \"File Download Missing Content-Disposition\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"File download endpoints without Content-Disposition headers may render files inline, leading to XSS if the file contains HTML/JS.\",\n check(content, filePath) {\n if (!/(?:download|sendFile|send_file|pipe|createReadStream)/i.test(content)) return [];\n if (!/(?:\\/api\\/|routes?\\/|controllers?\\/|server\\.|handler)/i.test(filePath)) return [];\n if (/Content-Disposition|attachment|download/i.test(content)) return [];\n return findMatches(content, /(?:sendFile|send_file|createReadStream|\\.pipe)\\s*\\(/gi, missingContentDisposition, filePath, () =>\n \"Set Content-Disposition: attachment header on file downloads: res.setHeader('Content-Disposition', 'attachment; filename=\\\"file.pdf\\\"').\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC090 – Open Redirect via Host Header\n// ────────────────────────────────────────────\n\nconst hostHeaderRedirect: CustomRule = {\n id: \"VC090\",\n title: \"Open Redirect via Host Header\",\n severity: \"high\",\n category: \"Injection\",\n description: \"Using req.headers.host to construct redirect URLs allows attackers to inject a malicious host header, redirecting users to phishing sites.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n const matches: RuleMatch[] = [];\n if (/req\\.headers\\.host|req\\.get\\s*\\(\\s*[\"']host[\"']\\)/i.test(content) && /redirect|location/i.test(content)) {\n matches.push(...findMatches(content, /req\\.headers\\.host|req\\.get\\s*\\(\\s*[\"']host[\"']\\)/gi, hostHeaderRedirect, filePath, () =>\n \"Don't use req.headers.host for redirects — it's attacker-controlled. Use a hardcoded domain or environment variable.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC091 – Race Condition / TOCTOU\n// ────────────────────────────────────────────\n\nconst raceCondition: CustomRule = {\n id: \"VC091\",\n title: \"Potential Race Condition (TOCTOU)\",\n severity: \"high\",\n category: \"Authorization\",\n description: \"Check-then-act patterns (e.g., checking if a file exists then writing to it) are vulnerable to race conditions where state changes between the check and the action.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /(?:existsSync|exists)\\s*\\([^)]+\\)[\\s\\S]{0,50}(?:writeFileSync|writeFile|unlinkSync|unlink|renameSync)\\s*\\(/g,\n /os\\.path\\.exists\\s*\\([^)]+\\)[\\s\\S]{0,50}open\\s*\\(/g,\n /File\\.exists\\?\\s*\\([^)]+\\)[\\s\\S]{0,50}File\\.(?:write|delete)/g,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, raceCondition, filePath, () =>\n \"Use atomic operations instead of check-then-act. For files: use fs.open with 'wx' flag (exclusive create), or use file locks.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC092 – Unsafe Object.assign from User Input\n// ────────────────────────────────────────────\n\nconst unsafeObjectAssign: CustomRule = {\n id: \"VC092\",\n title: \"Unsafe Object Spread from User Input\",\n severity: \"medium\",\n category: \"Injection\",\n description: \"Spreading request body into a new object can copy __proto__, constructor, or other dangerous properties, enabling prototype pollution.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /Object\\.assign\\s*\\(\\s*\\{\\s*\\}\\s*,\\s*(?:req\\.(?:body|query|params)|body|input)\\s*\\)/gi,\n /\\{\\s*\\.\\.\\.(?:req\\.(?:body|query|params)|body|input)\\s*\\}/gi,\n ];\n const hasSafe = /omit.*__proto__|sanitize|pick\\(|lodash\\.pick|stripProto/i.test(content);\n if (hasSafe) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, unsafeObjectAssign, filePath, () =>\n \"Explicitly pick allowed properties instead of spreading: const { name, email } = req.body; const safe = { name, email };\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC093 – Unprotected File Download Endpoint\n// ────────────────────────────────────────────\n\nconst unprotectedDownload: CustomRule = {\n id: \"VC093\",\n title: \"File Download Without Path Validation\",\n severity: \"medium\",\n category: \"Authorization\",\n description: \"File download endpoints that accept user-controlled filenames without path validation allow directory traversal to read arbitrary files.\",\n check(content, filePath) {\n if (!/(?:download|sendFile|send_file)/i.test(content)) return [];\n if (!/(?:\\/api\\/|routes?\\/|controllers?\\/|server\\.|handler)/i.test(filePath)) return [];\n const matches: RuleMatch[] = [];\n // sendFile/download with user input\n if (/(?:sendFile|download|send_file)\\s*\\([^)]*(?:req\\.|params\\.|query\\.|body\\.)/i.test(content)) {\n const hasValidation = /path\\.resolve|path\\.normalize|path\\.join.*__dirname|realpath|includes\\s*\\(\\s*[\"']\\.\\./i.test(content);\n if (!hasValidation) {\n matches.push(...findMatches(content, /(?:sendFile|download|send_file)\\s*\\(/gi, unprotectedDownload, filePath, () =>\n \"Validate file paths: const safePath = path.resolve(DOWNLOAD_DIR, filename); if (!safePath.startsWith(DOWNLOAD_DIR)) throw new Error('Invalid path');\"\n ));\n }\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC094 – Command Injection\n// ────────────────────────────────────────────\n\nconst commandInjection: CustomRule = {\n id: \"VC094\",\n title: \"Potential Command Injection\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"Passing user input to shell commands (exec, system, child_process) allows attackers to execute arbitrary system commands.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n // Node.js\n /(?:exec|execSync)\\s*\\(\\s*(?:`[^`]*\\$\\{|[\"'][^\"']*\\+\\s*(?:req\\.|body\\.|input|params|args|user))/gi,\n /child_process.*exec\\s*\\(\\s*(?![\"'`])/g,\n // Python\n /os\\.system\\s*\\(\\s*(?![\"'`].*[\"'`]\\s*\\))/g,\n /subprocess\\.(?:call|run|Popen)\\s*\\([^)]*shell\\s*=\\s*True/gi,\n // Ruby\n /system\\s*\\(\\s*[\"'].*#\\{/g,\n ];\n const hasSafe = /execFile|spawn|escapeshellarg|shlex\\.quote|shellEscape/i.test(content);\n if (hasSafe) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, commandInjection, filePath, () =>\n \"Use execFile/spawn instead of exec (avoids shell). Never concatenate user input into shell commands. Use parameterized arguments.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC095 – Hardcoded CORS Origin Localhost\n// ────────────────────────────────────────────\n\nconst corsLocalhost: CustomRule = {\n id: \"VC095\",\n title: \"Hardcoded Localhost CORS Origin\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Hardcoded localhost CORS origins in production code allow any local process to make authenticated requests to your API.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\") || filePath.includes(\".env\")) return [];\n if (!/origin/i.test(content)) return [];\n return findMatches(content, /origin\\s*[:=]\\s*[\"'`]http:\\/\\/localhost/gi, corsLocalhost, filePath, () =>\n \"Use environment variables for CORS origins: origin: process.env.ALLOWED_ORIGIN. Remove localhost from production configs.\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC096 – Unencrypted gRPC\n// ────────────────────────────────────────────\n\nconst insecureGRPC: CustomRule = {\n id: \"VC096\",\n title: \"Unencrypted gRPC Channel\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Using insecure gRPC channels transmits data including credentials in plaintext.\",\n check(content, filePath) {\n if (!/grpc/i.test(content)) return [];\n return findMatches(content, /(?:insecure_channel|createInsecure|grpc\\.Insecure)/gi, insecureGRPC, filePath, () =>\n \"Use encrypted gRPC channels: grpc.ssl_channel_credentials() or grpc.credentials.createSsl().\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// COMPLIANCE MAPPING (OWASP Top 10 + CWE)\n// ────────────────────────────────────────────\n\nexport const complianceMap: Record<string, { owasp: string; cwe: string }> = {\n VC001: { owasp: \"A07:2021\", cwe: \"CWE-798\" },\n VC002: { owasp: \"A05:2021\", cwe: \"CWE-200\" },\n VC003: { owasp: \"A01:2021\", cwe: \"CWE-862\" },\n VC004: { owasp: \"A01:2021\", cwe: \"CWE-284\" },\n VC005: { owasp: \"A08:2021\", cwe: \"CWE-345\" },\n VC006: { owasp: \"A03:2021\", cwe: \"CWE-89\" },\n VC007: { owasp: \"A03:2021\", cwe: \"CWE-79\" },\n VC008: { owasp: \"A04:2021\", cwe: \"CWE-770\" },\n VC009: { owasp: \"A05:2021\", cwe: \"CWE-942\" },\n VC010: { owasp: \"A01:2021\", cwe: \"CWE-602\" },\n VC011: { owasp: \"A07:2021\", cwe: \"CWE-798\" },\n VC012: { owasp: \"A05:2021\", cwe: \"CWE-200\" },\n VC013: { owasp: \"A01:2021\", cwe: \"CWE-269\" },\n VC014: { owasp: \"A05:2021\", cwe: \"CWE-538\" },\n VC015: { owasp: \"A03:2021\", cwe: \"CWE-95\" },\n VC016: { owasp: \"A01:2021\", cwe: \"CWE-601\" },\n VC017: { owasp: \"A05:2021\", cwe: \"CWE-614\" },\n VC018: { owasp: \"A07:2021\", cwe: \"CWE-798\" },\n VC019: { owasp: \"A05:2021\", cwe: \"CWE-693\" },\n VC020: { owasp: \"A05:2021\", cwe: \"CWE-1021\" },\n VC021: { owasp: \"A01:2021\", cwe: \"CWE-22\" },\n VC022: { owasp: \"A03:2021\", cwe: \"CWE-79\" },\n VC023: { owasp: \"A08:2021\", cwe: \"CWE-1321\" },\n VC024: { owasp: \"A04:2021\", cwe: \"CWE-770\" },\n VC025: { owasp: \"A03:2021\", cwe: \"CWE-22\" },\n VC026: { owasp: \"A05:2021\", cwe: \"CWE-693\" },\n VC027: { owasp: \"A05:2021\", cwe: \"CWE-693\" },\n VC028: { owasp: \"A07:2021\", cwe: \"CWE-20\" },\n VC029: { owasp: \"A08:2021\", cwe: \"CWE-20\" },\n VC030: { owasp: \"A08:2021\", cwe: \"CWE-502\" },\n VC031: { owasp: \"A02:2021\", cwe: \"CWE-321\" },\n VC032: { owasp: \"A05:2021\", cwe: \"CWE-319\" },\n VC033: { owasp: \"A05:2021\", cwe: \"CWE-215\" },\n VC034: { owasp: \"A02:2021\", cwe: \"CWE-338\" },\n VC035: { owasp: \"A01:2021\", cwe: \"CWE-601\" },\n VC036: { owasp: \"A04:2021\", cwe: \"CWE-755\" },\n VC037: { owasp: \"A09:2021\", cwe: \"CWE-209\" },\n VC038: { owasp: \"A04:2021\", cwe: \"CWE-434\" },\n VC039: { owasp: \"A06:2021\", cwe: \"CWE-1104\" },\n VC040: { owasp: \"A05:2021\", cwe: \"CWE-538\" },\n VC041: { owasp: \"A10:2021\", cwe: \"CWE-918\" },\n VC042: { owasp: \"A01:2021\", cwe: \"CWE-915\" },\n VC043: { owasp: \"A02:2021\", cwe: \"CWE-208\" },\n VC044: { owasp: \"A09:2021\", cwe: \"CWE-117\" },\n VC045: { owasp: \"A07:2021\", cwe: \"CWE-521\" },\n VC046: { owasp: \"A07:2021\", cwe: \"CWE-384\" },\n VC047: { owasp: \"A07:2021\", cwe: \"CWE-307\" },\n VC048: { owasp: \"A03:2021\", cwe: \"CWE-943\" },\n VC049: { owasp: \"A07:2021\", cwe: \"CWE-798\" },\n VC050: { owasp: \"A02:2021\", cwe: \"CWE-319\" },\n VC051: { owasp: \"A05:2021\", cwe: \"CWE-200\" },\n VC052: { owasp: \"A04:2021\", cwe: \"CWE-770\" },\n VC053: { owasp: \"A05:2021\", cwe: \"CWE-798\" },\n VC054: { owasp: \"A07:2021\", cwe: \"CWE-922\" },\n VC055: { owasp: \"A05:2021\", cwe: \"CWE-540\" },\n VC056: { owasp: \"A05:2021\", cwe: \"CWE-1021\" },\n VC057: { owasp: \"A01:2021\", cwe: \"CWE-269\" },\n VC058: { owasp: \"A05:2021\", cwe: \"CWE-250\" },\n VC059: { owasp: \"A05:2021\", cwe: \"CWE-284\" },\n VC060: { owasp: \"A02:2021\", cwe: \"CWE-328\" },\n VC061: { owasp: \"A02:2021\", cwe: \"CWE-295\" },\n VC062: { owasp: \"A02:2021\", cwe: \"CWE-321\" },\n VC063: { owasp: \"A03:2021\", cwe: \"CWE-79\" },\n VC064: { owasp: \"A01:2021\", cwe: \"CWE-862\" },\n VC065: { owasp: \"A01:2021\", cwe: \"CWE-862\" },\n VC066: { owasp: \"A07:2021\", cwe: \"CWE-798\" },\n VC067: { owasp: \"A01:2021\", cwe: \"CWE-601\" },\n VC068: { owasp: \"A07:2021\", cwe: \"CWE-922\" },\n VC069: { owasp: \"A02:2021\", cwe: \"CWE-295\" },\n VC070: { owasp: \"A05:2021\", cwe: \"CWE-489\" },\n VC071: { owasp: \"A05:2021\", cwe: \"CWE-215\" },\n VC072: { owasp: \"A07:2021\", cwe: \"CWE-798\" },\n VC073: { owasp: \"A08:2021\", cwe: \"CWE-502\" },\n VC074: { owasp: \"A01:2021\", cwe: \"CWE-352\" },\n VC075: { owasp: \"A03:2021\", cwe: \"CWE-78\" },\n VC076: { owasp: \"A07:2021\", cwe: \"CWE-798\" },\n VC077: { owasp: \"A05:2021\", cwe: \"CWE-942\" },\n VC078: { owasp: \"A05:2021\", cwe: \"CWE-250\" },\n VC079: { owasp: \"A02:2021\", cwe: \"CWE-327\" },\n VC080: { owasp: \"A04:2021\", cwe: \"CWE-1333\" },\n VC081: { owasp: \"A03:2021\", cwe: \"CWE-611\" },\n VC082: { owasp: \"A03:2021\", cwe: \"CWE-94\" },\n VC083: { owasp: \"A08:2021\", cwe: \"CWE-502\" },\n VC084: { owasp: \"A06:2021\", cwe: \"CWE-353\" },\n VC085: { owasp: \"A01:2021\", cwe: \"CWE-862\" },\n VC086: { owasp: \"A02:2021\", cwe: \"CWE-319\" },\n VC087: { owasp: \"A05:2021\", cwe: \"CWE-311\" },\n VC088: { owasp: \"A07:2021\", cwe: \"CWE-598\" },\n VC089: { owasp: \"A05:2021\", cwe: \"CWE-430\" },\n VC090: { owasp: \"A01:2021\", cwe: \"CWE-601\" },\n VC091: { owasp: \"A04:2021\", cwe: \"CWE-367\" },\n VC092: { owasp: \"A08:2021\", cwe: \"CWE-1321\" },\n VC093: { owasp: \"A01:2021\", cwe: \"CWE-22\" },\n VC094: { owasp: \"A03:2021\", cwe: \"CWE-78\" },\n VC095: { owasp: \"A05:2021\", cwe: \"CWE-942\" },\n VC096: { owasp: \"A02:2021\", cwe: \"CWE-319\" },\n};\n\n// ────────────────────────────────────────────\n// EXPORT ALL RULES\n// ────────────────────────────────────────────\n\nexport const allRules: CustomRule[] = [\n hardcodedSecrets,\n exposedEnvFile,\n missingAuthMiddleware,\n supabaseNoRLS,\n stripeWebhookUnprotected,\n sqlInjection,\n xssVulnerability,\n noRateLimiting,\n corsWildcard,\n clientSideAuth,\n nextPublicSecret,\n firebaseClientConfig,\n supabaseAnonAdmin,\n envNotGitignored,\n evalUsage,\n unvalidatedRedirect,\n insecureCookies,\n exposedAuthSecret,\n insecureElectronWindow,\n missingCSP,\n ipcPathTraversal,\n unsanitizedHTMLExport,\n prototypePollution,\n missingFileSizeLimits,\n unsanitizedFilenames,\n electronNavigationUnrestricted,\n missingSecurityMeta,\n unvalidatedAPIParams,\n unvalidatedEventData,\n insecureDeserialization,\n hardcodedJWTSecret,\n missingHTTPS,\n exposedDebugMode,\n insecureRandomness,\n openRedirectParams,\n missingErrorBoundary,\n exposedStackTraces,\n insecureFileUpload,\n missingLockFile,\n exposedGitDir,\n ssrfVulnerability,\n massAssignment,\n timingAttack,\n logInjection,\n weakPasswordRequirements,\n sessionFixation,\n missingBruteForce,\n nosqlInjection,\n exposedDBCredentials,\n missingDBEncryption,\n graphqlIntrospection,\n missingRequestSizeLimit,\n hardcodedIPAllowlist,\n sensitiveLocalStorage,\n exposedSourceMaps,\n clickjacking,\n overlyPermissiveIAM,\n dockerRunAsRoot,\n exposedDockerPorts,\n weakHashing,\n disabledTLSVerification,\n hardcodedEncryptionKey,\n dangerousInnerHTML,\n exposedServerActions,\n unprotectedAPIRoutes,\n clientComponentSecret,\n insecureDeepLink,\n sensitiveAsyncStorage,\n missingCertPinning,\n androidDebuggable,\n djangoDebug,\n flaskSecretKey,\n pickleDeserialization,\n missingCSRF,\n githubActionsInjection,\n secretsInCI,\n corsServerless,\n k8sPrivileged,\n jwtAlgConfusion,\n regexDos,\n xxeVulnerability,\n ssti,\n javaDeserialization,\n missingSRI,\n exposedAdminRoutes,\n insecureWebSocket,\n missingHSTS,\n sensitiveURLParams,\n missingContentDisposition,\n hostHeaderRedirect,\n raceCondition,\n unsafeObjectAssign,\n unprotectedDownload,\n commandInjection,\n corsLocalhost,\n insecureGRPC,\n];\n\nexport function runCustomRules(\n content: string,\n filePath: string,\n disabledRules: string[] = [],\n): Finding[] {\n const findings: Finding[] = [];\n\n // Skip files that ARE security scanners (avoid scanning ourselves)\n if (/function runScan\\(files\\)|export function runCustomRules/.test(content) && /const (?:rules|allRules)\\s*[:=]/.test(content) && /findMatches/.test(content)) {\n return findings;\n }\n\n for (const rule of allRules) {\n if (disabledRules.includes(rule.id)) continue;\n\n const matches = rule.check(content, filePath);\n const compliance = complianceMap[rule.id];\n for (const match of matches) {\n findings.push({\n id: `${match.rule}-${match.file}:${match.line}`,\n rule: match.rule,\n severity: match.severity,\n title: match.title,\n description: rule.description,\n file: match.file,\n line: match.line,\n column: match.column,\n snippet: match.snippet,\n fix: match.fix,\n category: match.category,\n source: \"custom\",\n owasp: compliance?.owasp,\n cwe: compliance?.cwe,\n });\n }\n }\n\n return findings;\n}\n","import { execFile } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { readFile, writeFile, mkdtemp, rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport type { Finding, Severity } from \"../types.js\";\n\ninterface SemgrepSarifResult {\n runs?: Array<{\n results?: Array<{\n ruleId?: string;\n level?: string;\n message?: { text?: string };\n locations?: Array<{\n physicalLocation?: {\n artifactLocation?: { uri?: string };\n region?: {\n startLine?: number;\n startColumn?: number;\n snippet?: { text?: string };\n };\n };\n }>;\n }>;\n }>;\n}\n\nconst SEVERITY_MAP: Record<string, Severity> = {\n error: \"high\",\n warning: \"medium\",\n note: \"low\",\n none: \"info\",\n};\n\nfunction semgrepSeverityToXploitscan(level: string): Severity {\n return SEVERITY_MAP[level] ?? \"medium\";\n}\n\nasync function isSemgrepInstalled(): Promise<boolean> {\n return new Promise((resolve) => {\n execFile(\"semgrep\", [\"--version\"], (error) => {\n resolve(!error);\n });\n });\n}\n\nexport async function runSemgrep(\n directory: string,\n customRulesDir?: string,\n): Promise<{ findings: Finding[]; available: boolean }> {\n const installed = await isSemgrepInstalled();\n if (!installed) {\n return { findings: [], available: false };\n }\n\n const findings: Finding[] = [];\n\n // Create a temp directory for SARIF output\n const tmpDir = await mkdtemp(join(tmpdir(), \"xploitscan-semgrep-\"));\n const sarifPath = join(tmpDir, \"results.sarif\");\n\n try {\n // Build semgrep args\n const args = [\n \"scan\",\n \"--sarif\",\n \"--output\", sarifPath,\n \"--quiet\",\n \"--no-git-ignore\", // We handle .gitignore ourselves\n \"--timeout\", \"30\",\n \"--max-target-bytes\", \"1000000\",\n ];\n\n // Use auto config (community rules) + custom rules if available\n args.push(\"--config\", \"auto\");\n\n if (customRulesDir && existsSync(customRulesDir)) {\n args.push(\"--config\", customRulesDir);\n }\n\n args.push(directory);\n\n // Run semgrep\n await new Promise<void>((resolve, reject) => {\n const proc = execFile(\n \"semgrep\",\n args,\n { timeout: 120_000, maxBuffer: 10 * 1024 * 1024 },\n (error, _stdout, stderr) => {\n // Semgrep returns exit code 1 when findings exist — that's fine\n if (error && error.code !== 1) {\n reject(new Error(`Semgrep failed: ${stderr || error.message}`));\n } else {\n resolve();\n }\n },\n );\n });\n\n // Parse SARIF output\n if (!existsSync(sarifPath)) return { findings, available: true };\n\n const sarifContent = await readFile(sarifPath, \"utf-8\");\n const sarif: SemgrepSarifResult = JSON.parse(sarifContent);\n\n for (const run of sarif.runs ?? []) {\n for (const result of run.results ?? []) {\n const location = result.locations?.[0]?.physicalLocation;\n const filePath = location?.artifactLocation?.uri ?? \"unknown\";\n const line = location?.region?.startLine ?? 1;\n const snippet = location?.region?.snippet?.text ?? \"\";\n\n // Determine category from rule ID\n const ruleId = result.ruleId ?? \"semgrep\";\n const category = categorizeSemgrepRule(ruleId);\n\n findings.push({\n id: `SG-${filePath}:${line}:${ruleId}`,\n rule: ruleId,\n severity: semgrepSeverityToXploitscan(result.level ?? \"warning\"),\n title: truncate(result.message?.text ?? ruleId, 100),\n description: result.message?.text ?? \"\",\n file: filePath.replace(/^file:\\/\\//, \"\"),\n line,\n column: location?.region?.startColumn,\n snippet: formatSnippet(snippet, line),\n category,\n source: \"semgrep\",\n });\n }\n }\n } finally {\n // Clean up temp directory\n await rm(tmpDir, { recursive: true, force: true }).catch(() => {});\n }\n\n return { findings, available: true };\n}\n\nfunction categorizeSemgrepRule(ruleId: string): string {\n const id = ruleId.toLowerCase();\n if (id.includes(\"sql\") || id.includes(\"injection\") || id.includes(\"xss\") || id.includes(\"command\")) return \"Injection\";\n if (id.includes(\"auth\") || id.includes(\"session\")) return \"Authentication\";\n if (id.includes(\"crypto\") || id.includes(\"hash\") || id.includes(\"random\")) return \"Cryptography\";\n if (id.includes(\"cors\") || id.includes(\"header\") || id.includes(\"config\")) return \"Configuration\";\n if (id.includes(\"secret\") || id.includes(\"key\") || id.includes(\"password\") || id.includes(\"credential\")) return \"Secrets\";\n if (id.includes(\"path\") || id.includes(\"traversal\") || id.includes(\"file\")) return \"Path Traversal\";\n if (id.includes(\"deserial\")) return \"Deserialization\";\n return \"Security\";\n}\n\nfunction formatSnippet(text: string, line: number): string {\n if (!text) return \"\";\n const lines = text.split(\"\\n\");\n return lines\n .map((l, i) => {\n const num = line + i;\n return ` ${num.toString().padStart(4)} | ${l}`;\n })\n .join(\"\\n\");\n}\n\nfunction truncate(str: string, max: number): string {\n return str.length > max ? str.substring(0, max - 3) + \"...\" : str;\n}\n","import { execFile } from \"node:child_process\";\nimport { readFile, mkdtemp, rm } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport type { Finding, Severity } from \"../types.js\";\nimport { getSnippet, readFileContents } from \"../utils/files.js\";\n\ninterface GitleaksResult {\n Description: string;\n File: string;\n StartLine: number;\n EndLine: number;\n StartColumn: number;\n EndColumn: number;\n Match: string;\n Secret: string;\n RuleID: string;\n Entropy: number;\n Tags?: string[];\n}\n\nconst RULE_SEVERITY: Record<string, Severity> = {\n \"aws-access-token\": \"critical\",\n \"aws-secret-access-key\": \"critical\",\n \"stripe-access-token\": \"critical\",\n \"github-pat\": \"critical\",\n \"private-key\": \"critical\",\n \"generic-api-key\": \"high\",\n \"slack-webhook\": \"high\",\n \"twilio-api-key\": \"high\",\n \"sendgrid-api-key\": \"high\",\n \"shopify-access-token\": \"high\",\n \"gcp-api-key\": \"critical\",\n \"heroku-api-key\": \"high\",\n \"npm-access-token\": \"critical\",\n \"pypi-upload-token\": \"critical\",\n \"telegram-bot-api-token\": \"high\",\n \"discord-bot-token\": \"high\",\n \"firebase-api-key\": \"high\",\n};\n\nasync function isGitleaksInstalled(): Promise<boolean> {\n return new Promise((resolve) => {\n execFile(\"gitleaks\", [\"version\"], (error) => {\n resolve(!error);\n });\n });\n}\n\nexport async function runGitleaks(\n directory: string,\n): Promise<{ findings: Finding[]; available: boolean }> {\n const installed = await isGitleaksInstalled();\n if (!installed) {\n return { findings: [], available: false };\n }\n\n const findings: Finding[] = [];\n const tmpDir = await mkdtemp(join(tmpdir(), \"xploitscan-gitleaks-\"));\n const reportPath = join(tmpDir, \"results.json\");\n\n try {\n const args = [\n \"detect\",\n \"--source\", directory,\n \"--report-path\", reportPath,\n \"--report-format\", \"json\",\n \"--no-git\",\n \"--exit-code\", \"0\", // Don't fail on findings\n ];\n\n await new Promise<void>((resolve, reject) => {\n execFile(\n \"gitleaks\",\n args,\n { timeout: 60_000, maxBuffer: 10 * 1024 * 1024 },\n (error, _stdout, stderr) => {\n if (error) {\n const sanitizedError = (stderr || error.message).slice(0, 200);\n reject(new Error(`Gitleaks failed: ${sanitizedError}`));\n } else {\n resolve();\n }\n },\n );\n });\n\n // Parse results\n if (!existsSync(reportPath)) return { findings, available: true };\n\n const reportContent = await readFile(reportPath, \"utf-8\");\n if (!reportContent.trim()) return { findings, available: true };\n\n const results: GitleaksResult[] = JSON.parse(reportContent);\n\n for (const result of results) {\n const filePath = result.File;\n const line = result.StartLine + 1; // Gitleaks uses 0-based lines\n const severity = RULE_SEVERITY[result.RuleID] ?? \"high\";\n\n // Read file content for snippet\n const content = readFileContents(directory, filePath);\n const snippet = content ? getSnippet(content, line) : ` ${result.Match}`;\n\n // Redact the actual secret in the description\n const redactedSecret = result.Secret.length > 8\n ? result.Secret.substring(0, 4) + \"...\" + result.Secret.substring(result.Secret.length - 4)\n : \"****\";\n\n findings.push({\n id: `GL-${filePath}:${line}:${result.RuleID}`,\n rule: `GL:${result.RuleID}`,\n severity,\n title: `${result.Description} (detected by Gitleaks)`,\n description: `A secret matching \"${result.RuleID}\" pattern was found: ${redactedSecret}. If this is a real credential, it may already be compromised. Rotate it immediately and move it to environment variables.`,\n file: filePath,\n line,\n column: result.StartColumn,\n snippet,\n fix: `1. Rotate this credential immediately (it may be in git history)\\n2. Move it to a .env file: ${result.RuleID.toUpperCase().replace(/-/g, \"_\")}=<new-value>\\n3. Add .env to .gitignore\\n4. Remove from git history: git filter-branch or BFG Repo Cleaner`,\n category: \"Secrets\",\n source: \"gitleaks\",\n });\n }\n } finally {\n await rm(tmpDir, { recursive: true, force: true }).catch(() => {});\n }\n\n return { findings, available: true };\n}\n","import Anthropic from \"@anthropic-ai/sdk\";\nimport type { Finding, Severity } from \"../types.js\";\n\nconst SYSTEM_PROMPT = `You are a security auditor specializing in code generated by AI tools (Cursor, Lovable, Bolt, Replit, Claude). Your audience is non-expert developers who may not understand security jargon.\n\nAnalyze the provided code for security vulnerabilities. Focus on issues that AI code generators commonly introduce:\n- Missing authentication/authorization\n- Exposed secrets or credentials\n- SQL injection, XSS, and other injection flaws\n- Insecure direct object references (IDOR)\n- Missing input validation\n- Insecure defaults (permissive CORS, no rate limiting)\n- Client-side security checks without server-side enforcement\n- Supabase RLS misconfigurations\n- Unprotected payment/webhook endpoints\n\nFor each vulnerability found, respond with a JSON array of objects:\n{\n \"title\": \"Short, clear title\",\n \"severity\": \"critical|high|medium|low\",\n \"line\": <approximate line number>,\n \"description\": \"Plain-English explanation a non-developer can understand. What's the risk? What could an attacker do?\",\n \"fix\": \"Step-by-step fix instructions with code example if helpful\",\n \"category\": \"Secrets|Authentication|Authorization|Injection|Configuration|Payment Security|Data Exposure\"\n}\n\nIf no vulnerabilities are found, return an empty array: []\n\nRules:\n- Only report real, exploitable issues — no theoretical concerns\n- Be specific about what an attacker could do\n- Explain fixes in beginner-friendly language\n- Reference specific line numbers`;\n\nexport async function analyzeWithAI(\n files: { path: string; content: string }[],\n existingFindings: Finding[],\n): Promise<Finding[]> {\n const apiKey = process.env.ANTHROPIC_API_KEY;\n if (!apiKey) return [];\n\n const client = new Anthropic();\n\n // Build context: send files with existing findings for dedup\n const existingRules = new Set(\n existingFindings.map((f) => `${f.file}:${f.line}:${f.rule}`),\n );\n\n // Batch files into chunks to stay within token limits (~50KB per chunk)\n const chunks = chunkFiles(files, 50_000);\n const allFindings: Finding[] = [];\n\n for (const chunk of chunks) {\n const fileContext = chunk\n .map((f) => `--- ${f.path} ---\\n${f.content}`)\n .join(\"\\n\\n\");\n\n const existingNote = existingFindings.length > 0\n ? `\\n\\nThe following issues have already been found by static rules (do NOT duplicate these):\\n${existingFindings.map((f) => `- ${f.file}:${f.line} — ${f.title}`).join(\"\\n\")}`\n : \"\";\n\n try {\n const response = await client.messages.create({\n model: \"claude-sonnet-4-5-20250514\",\n max_tokens: 4096,\n messages: [\n {\n role: \"user\",\n content: `Analyze these source files for security vulnerabilities:${existingNote}\\n\\n${fileContext}`,\n },\n ],\n system: SYSTEM_PROMPT,\n });\n\n const text = response.content\n .filter((block): block is Anthropic.TextBlock => block.type === \"text\")\n .map((block) => block.text)\n .join(\"\");\n\n // Extract JSON from response (handles markdown code blocks)\n const jsonMatch = text.match(/\\[[\\s\\S]*\\]/);\n if (!jsonMatch) continue;\n\n const parsed = JSON.parse(jsonMatch[0]) as Array<{\n title: string;\n severity: Severity;\n line: number;\n description: string;\n fix: string;\n category: string;\n }>;\n\n for (const item of parsed) {\n // Find which file this finding belongs to\n const matchFile = chunk.find((f) => {\n const lines = f.content.split(\"\\n\");\n return item.line <= lines.length;\n });\n const file = matchFile?.path ?? chunk[0].path;\n\n const key = `${file}:${item.line}:AI`;\n if (existingRules.has(key)) continue;\n\n const content = chunk.find((f) => f.path === file)?.content ?? \"\";\n const lines = content.split(\"\\n\");\n const snippetStart = Math.max(0, item.line - 3);\n const snippetEnd = Math.min(lines.length, item.line + 2);\n const snippet = lines\n .slice(snippetStart, snippetEnd)\n .map((l, i) => {\n const num = snippetStart + i + 1;\n const marker = num === item.line ? \">\" : \" \";\n return `${marker} ${num.toString().padStart(4)} | ${l}`;\n })\n .join(\"\\n\");\n\n allFindings.push({\n id: `AI-${file}:${item.line}`,\n rule: \"AI\",\n severity: item.severity,\n title: item.title,\n description: item.description,\n file,\n line: item.line,\n snippet,\n fix: item.fix,\n category: item.category,\n source: \"ai\",\n });\n }\n } catch (error) {\n // AI analysis failed for this chunk — continue with others\n if (error instanceof Error && error.message.includes(\"API key\")) {\n throw new Error(\n \"Invalid ANTHROPIC_API_KEY. Get one at https://console.anthropic.com/\",\n );\n }\n }\n }\n\n return allFindings;\n}\n\nfunction chunkFiles(\n files: { path: string; content: string }[],\n maxChars: number,\n): { path: string; content: string }[][] {\n const chunks: { path: string; content: string }[][] = [];\n let current: { path: string; content: string }[] = [];\n let currentSize = 0;\n\n for (const file of files) {\n if (currentSize + file.content.length > maxChars && current.length > 0) {\n chunks.push(current);\n current = [];\n currentSize = 0;\n }\n current.push(file);\n currentSize += file.content.length;\n }\n\n if (current.length > 0) chunks.push(current);\n return chunks;\n}\n","/**\n * AST-based JavaScript/TypeScript analyzer\n * Uses regex-based pseudo-AST parsing (no external deps) to understand code structure\n * and reduce false positives from comments, strings, and non-executable code.\n */\n\nimport type { Finding, Severity } from \"../types.js\";\n\n// ────────────────────────────────────────────\n// Code Structure Detection\n// ────────────────────────────────────────────\n\ninterface CodeContext {\n isComment: boolean;\n isString: boolean;\n isImport: boolean;\n isTestFile: boolean;\n isTypeDefinition: boolean;\n functionScope: string | null;\n nearestAssignment: string | null;\n}\n\n/** Strip all comments from JS/TS/Python code to prevent false positives */\nexport function stripComments(content: string): string {\n let result = \"\";\n let i = 0;\n let inSingleQuote = false;\n let inDoubleQuote = false;\n let inTemplate = false;\n let inSingleLineComment = false;\n let inMultiLineComment = false;\n\n while (i < content.length) {\n const ch = content[i];\n const next = content[i + 1];\n\n if (inSingleLineComment) {\n if (ch === \"\\n\") {\n inSingleLineComment = false;\n result += ch;\n }\n i++;\n continue;\n }\n\n if (inMultiLineComment) {\n if (ch === \"*\" && next === \"/\") {\n inMultiLineComment = false;\n i += 2;\n } else {\n if (ch === \"\\n\") result += ch; // preserve line numbers\n i++;\n }\n continue;\n }\n\n if (inSingleQuote) {\n result += ch;\n if (ch === \"'\" && content[i - 1] !== \"\\\\\") inSingleQuote = false;\n i++;\n continue;\n }\n\n if (inDoubleQuote) {\n result += ch;\n if (ch === '\"' && content[i - 1] !== \"\\\\\") inDoubleQuote = false;\n i++;\n continue;\n }\n\n if (inTemplate) {\n result += ch;\n if (ch === \"`\" && content[i - 1] !== \"\\\\\") inTemplate = false;\n i++;\n continue;\n }\n\n // Check for comment starts\n if (ch === \"/\" && next === \"/\") {\n inSingleLineComment = true;\n i += 2;\n continue;\n }\n if (ch === \"/\" && next === \"*\") {\n inMultiLineComment = true;\n i += 2;\n continue;\n }\n // Python/YAML comments\n if (ch === \"#\" && !inSingleQuote && !inDoubleQuote) {\n inSingleLineComment = true;\n i++;\n continue;\n }\n\n // Check for string starts\n if (ch === \"'\") inSingleQuote = true;\n if (ch === '\"') inDoubleQuote = true;\n if (ch === \"`\") inTemplate = true;\n\n result += ch;\n i++;\n }\n\n return result;\n}\n\n/** Detect if a line index falls within a function body */\nexport function getFunctionScope(content: string, lineIndex: number): string | null {\n const lines = content.split(\"\\n\");\n // Walk backwards from the match line to find enclosing function\n for (let i = lineIndex; i >= 0; i--) {\n const line = lines[i];\n const funcMatch = line.match(/(?:function\\s+(\\w+)|(?:const|let|var)\\s+(\\w+)\\s*=\\s*(?:async\\s+)?(?:function|\\([^)]*\\)\\s*=>)|(\\w+)\\s*\\([^)]*\\)\\s*\\{)/);\n if (funcMatch) {\n return funcMatch[1] || funcMatch[2] || funcMatch[3] || \"anonymous\";\n }\n }\n return null;\n}\n\n/** Check if content between two positions has a validation/sanitization pattern */\nexport function hasValidationBetween(content: string, startLine: number, endLine: number): boolean {\n const lines = content.split(\"\\n\");\n const segment = lines.slice(startLine, endLine + 1).join(\"\\n\");\n return /(?:validate|sanitize|escape|check|verify|assert|ensure|guard|protect|filter|whitelist|allowlist|isValid|isAllowed|isSafe)/i.test(segment);\n}\n\n/** Detect data flow: does user input reach a dangerous sink? */\nexport function tracesUserInput(content: string, sinkLine: number, linesBack: number = 15): boolean {\n const lines = content.split(\"\\n\");\n const start = Math.max(0, sinkLine - linesBack);\n const segment = lines.slice(start, sinkLine + 1).join(\"\\n\");\n\n const userInputSources = /(?:req\\.(?:body|query|params|headers)|body\\.|input\\.|params\\.|args\\.|request\\.|formData|searchParams|useSearchParams|URLSearchParams)/i;\n return userInputSources.test(segment);\n}\n\n/** Extract all import/require statements to understand dependencies */\nexport function extractImports(content: string): string[] {\n const imports: string[] = [];\n const patterns = [\n /import\\s+.*?from\\s+[\"'`]([^\"'`]+)[\"'`]/g,\n /require\\s*\\(\\s*[\"'`]([^\"'`]+)[\"'`]\\s*\\)/g,\n ];\n for (const p of patterns) {\n let m;\n while ((m = p.exec(content)) !== null) {\n imports.push(m[1]);\n }\n }\n return imports;\n}\n\n/** Check if a file imports/uses a specific security middleware */\nexport function hasSecurityMiddleware(content: string): { auth: boolean; rateLimit: boolean; helmet: boolean; cors: boolean; csrf: boolean } {\n return {\n auth: /(?:requireAuth|isAuthenticated|authenticate|passport|jwt\\.verify|clerk|auth0|nextauth|session\\.user|getServerSession|getAuth|withAuth|authMiddleware)/i.test(content),\n rateLimit: /(?:rateLimit|rate-limit|express-rate-limit|throttle|slowDown|limiter)/i.test(content),\n helmet: /(?:helmet|security-headers|securityHeaders)/i.test(content),\n cors: /(?:cors\\(|corsMiddleware|allowedOrigins)/i.test(content),\n csrf: /(?:csrf|csurf|csrfToken|_csrf)/i.test(content),\n };\n}\n\n// ────────────────────────────────────────────\n// AST-Enhanced Rule Runner\n// ────────────────────────────────────────────\n\nexport interface ASTContext {\n strippedContent: string; // Code with comments removed\n imports: string[]; // All imports/requires\n middleware: ReturnType<typeof hasSecurityMiddleware>;\n isTestFile: boolean;\n isConfigFile: boolean;\n isScannerFile: boolean; // Self-detection: is this a security scanner?\n}\n\nexport function buildASTContext(content: string, filePath: string): ASTContext {\n return {\n strippedContent: stripComments(content),\n imports: extractImports(content),\n middleware: hasSecurityMiddleware(content),\n isTestFile: /(?:\\.test\\.|\\.spec\\.|__tests__|__mocks__|\\.stories\\.|fixtures?\\/|mocks?\\/|\\.cy\\.|\\.e2e\\.)/i.test(filePath),\n isConfigFile: /(?:\\.config\\.|config\\/|\\.rc$|tsconfig|next\\.config|vite\\.config|webpack\\.config)/i.test(filePath),\n isScannerFile: /(?:custom-rules|scanner|security-check|eslint-plugin|lint)/i.test(filePath) &&\n /(?:findMatches|check\\s*\\(content|rule\\.check|severity|category)/i.test(content),\n };\n}\n","/**\n * Dependency Vulnerability Scanner\n * Parses package.json, requirements.txt, Gemfile, etc. and checks\n * for known vulnerable packages and risky dependency patterns.\n */\n\nimport type { Finding } from \"../types.js\";\n\n// Known vulnerable packages and their details\n// Format: package -> { minSafeVersion, cve, severity, description }\ninterface VulnEntry {\n minSafe: string;\n cve: string;\n severity: \"critical\" | \"high\" | \"medium\" | \"low\";\n title: string;\n description: string;\n fix: string;\n}\n\n// Well-known vulnerable npm packages (manually curated, high-signal)\nconst KNOWN_VULN_NPM: Record<string, VulnEntry[]> = {\n \"lodash\": [{\n minSafe: \"4.17.21\", cve: \"CVE-2021-23337\", severity: \"critical\",\n title: \"Lodash Prototype Pollution\",\n description: \"lodash before 4.17.21 is vulnerable to prototype pollution via set, setWith, and zipObjectDeep.\",\n fix: \"Upgrade lodash to >= 4.17.21: npm install lodash@latest\"\n }],\n \"axios\": [{\n minSafe: \"1.6.0\", cve: \"CVE-2023-45857\", severity: \"high\",\n title: \"Axios CSRF Vulnerability\",\n description: \"axios before 1.6.0 inadvertently leaks XSRF-TOKEN cookie in cross-site requests.\",\n fix: \"Upgrade axios to >= 1.6.0: npm install axios@latest\"\n }],\n \"express\": [{\n minSafe: \"4.19.2\", cve: \"CVE-2024-29041\", severity: \"medium\",\n title: \"Express Open Redirect\",\n description: \"Express before 4.19.2 is vulnerable to open redirect via crafted URLs.\",\n fix: \"Upgrade express to >= 4.19.2: npm install express@latest\"\n }],\n \"jsonwebtoken\": [{\n minSafe: \"9.0.0\", cve: \"CVE-2022-23529\", severity: \"high\",\n title: \"jsonwebtoken Insecure Key Handling\",\n description: \"jsonwebtoken before 9.0.0 allows attackers to set secretOrPublicKey to a malicious object.\",\n fix: \"Upgrade jsonwebtoken to >= 9.0.0: npm install jsonwebtoken@latest\"\n }],\n \"node-fetch\": [{\n minSafe: \"2.6.7\", cve: \"CVE-2022-0235\", severity: \"high\",\n title: \"node-fetch Header Exposure\",\n description: \"node-fetch before 2.6.7 exposes authorization headers on redirect to different origin.\",\n fix: \"Upgrade node-fetch to >= 2.6.7 or switch to native fetch (Node 18+).\"\n }],\n \"minimatch\": [{\n minSafe: \"3.0.5\", cve: \"CVE-2022-3517\", severity: \"high\",\n title: \"Minimatch ReDoS\",\n description: \"minimatch before 3.0.5 is vulnerable to Regular Expression Denial of Service.\",\n fix: \"Upgrade minimatch to >= 3.0.5: npm install minimatch@latest\"\n }],\n \"moment\": [{\n minSafe: \"999.0.0\", cve: \"N/A\", severity: \"medium\",\n title: \"Moment.js is Deprecated\",\n description: \"moment.js is in maintenance mode with known path traversal issues. Consider alternatives.\",\n fix: \"Migrate to date-fns, dayjs, or Temporal API. See: https://momentjs.com/docs/#/-project-status/\"\n }],\n \"request\": [{\n minSafe: \"999.0.0\", cve: \"N/A\", severity: \"medium\",\n title: \"Request Package Deprecated\",\n description: \"The 'request' package is deprecated and no longer receives security updates.\",\n fix: \"Migrate to node-fetch, axios, got, or native fetch (Node 18+).\"\n }],\n \"underscore\": [{\n minSafe: \"1.13.6\", cve: \"CVE-2021-23358\", severity: \"high\",\n title: \"Underscore.js Arbitrary Code Execution\",\n description: \"underscore before 1.13.6 allows arbitrary code execution via the template function.\",\n fix: \"Upgrade underscore to >= 1.13.6 or migrate to lodash.\"\n }],\n \"tar\": [{\n minSafe: \"6.2.1\", cve: \"CVE-2024-28863\", severity: \"high\",\n title: \"Tar Path Traversal\",\n description: \"tar before 6.2.1 is vulnerable to denial of service via crafted archives.\",\n fix: \"Upgrade tar to >= 6.2.1: npm install tar@latest\"\n }],\n \"semver\": [{\n minSafe: \"7.5.2\", cve: \"CVE-2022-25883\", severity: \"medium\",\n title: \"Semver ReDoS\",\n description: \"semver before 7.5.2 is vulnerable to Regular Expression Denial of Service.\",\n fix: \"Upgrade semver to >= 7.5.2: npm install semver@latest\"\n }],\n \"xml2js\": [{\n minSafe: \"0.5.0\", cve: \"CVE-2023-0842\", severity: \"medium\",\n title: \"xml2js Prototype Pollution\",\n description: \"xml2js before 0.5.0 is vulnerable to prototype pollution when parsing XML.\",\n fix: \"Upgrade xml2js to >= 0.5.0: npm install xml2js@latest\"\n }],\n};\n\n// Known vulnerable Python packages\nconst KNOWN_VULN_PYTHON: Record<string, VulnEntry[]> = {\n \"django\": [{\n minSafe: \"4.2.11\", cve: \"CVE-2024-27351\", severity: \"high\",\n title: \"Django ReDoS in Truncator\",\n description: \"Django before 4.2.11 is vulnerable to Regular Expression Denial of Service.\",\n fix: \"Upgrade Django to >= 4.2.11: pip install Django --upgrade\"\n }],\n \"flask\": [{\n minSafe: \"2.3.2\", cve: \"CVE-2023-30861\", severity: \"high\",\n title: \"Flask Session Cookie Vulnerability\",\n description: \"Flask before 2.3.2 may set permanent session cookies on redirect responses.\",\n fix: \"Upgrade Flask to >= 2.3.2: pip install Flask --upgrade\"\n }],\n \"pillow\": [{\n minSafe: \"10.2.0\", cve: \"CVE-2023-50447\", severity: \"critical\",\n title: \"Pillow Arbitrary Code Execution\",\n description: \"Pillow before 10.2.0 is vulnerable to arbitrary code execution via crafted images.\",\n fix: \"Upgrade Pillow to >= 10.2.0: pip install Pillow --upgrade\"\n }],\n \"requests\": [{\n minSafe: \"2.31.0\", cve: \"CVE-2023-32681\", severity: \"medium\",\n title: \"Requests Proxy Header Leak\",\n description: \"requests before 2.31.0 leaks Proxy-Authorization headers to destination servers.\",\n fix: \"Upgrade requests to >= 2.31.0: pip install requests --upgrade\"\n }],\n \"pyyaml\": [{\n minSafe: \"6.0.1\", cve: \"CVE-2022-41316\", severity: \"high\",\n title: \"PyYAML Unsafe Loading\",\n description: \"PyYAML has known deserialization vulnerabilities. Always use yaml.safe_load().\",\n fix: \"Upgrade PyYAML to >= 6.0.1 and use yaml.safe_load() instead of yaml.load().\"\n }],\n \"jinja2\": [{\n minSafe: \"3.1.3\", cve: \"CVE-2024-22195\", severity: \"medium\",\n title: \"Jinja2 XSS Vulnerability\",\n description: \"Jinja2 before 3.1.3 is vulnerable to XSS via xmlattr filter.\",\n fix: \"Upgrade Jinja2 to >= 3.1.3: pip install Jinja2 --upgrade\"\n }],\n};\n\n// Risky patterns in dependency configs\ninterface DepPattern {\n id: string;\n title: string;\n severity: \"critical\" | \"high\" | \"medium\" | \"low\";\n description: string;\n fix: string;\n test: (content: string, filePath: string) => boolean;\n}\n\nconst DEP_PATTERNS: DepPattern[] = [\n {\n id: \"DEP001\", title: \"Wildcard Dependency Version\", severity: \"high\",\n description: \"Using '*' or 'latest' as a dependency version allows any version to be installed, including malicious ones.\",\n fix: \"Pin dependency versions: use exact (1.2.3) or caret (^1.2.3) versions, never '*' or 'latest'.\",\n test: (content, filePath) => filePath.endsWith(\"package.json\") && /[\"']\\*[\"']|[\"']latest[\"']/.test(content),\n },\n {\n id: \"DEP002\", title: \"Git Dependency Without Commit Hash\", severity: \"medium\",\n description: \"Git dependencies without a pinned commit hash can be replaced with malicious code.\",\n fix: \"Pin git dependencies to a specific commit: git+https://github.com/user/repo#commit-hash\",\n test: (content, filePath) => filePath.endsWith(\"package.json\") && /git\\+https?:\\/\\/[^#\"]+[\"']/.test(content),\n },\n {\n id: \"DEP003\", title: \"Postinstall Script in Package\", severity: \"medium\",\n description: \"postinstall scripts run automatically after npm install and can execute arbitrary code.\",\n fix: \"Audit postinstall scripts carefully. Use --ignore-scripts flag for untrusted packages.\",\n test: (content, filePath) => filePath.endsWith(\"package.json\") && /\"postinstall\"\\s*:/.test(content),\n },\n {\n id: \"DEP004\", title: \"No Package Lock File\", severity: \"medium\",\n description: \"Without a lockfile, npm install may resolve different versions on different machines.\",\n fix: \"Commit your lockfile (package-lock.json, pnpm-lock.yaml, or yarn.lock).\",\n test: (content, filePath) => filePath.endsWith(\".gitignore\") && /package-lock\\.json|pnpm-lock\\.yaml|yarn\\.lock/.test(content),\n },\n {\n id: \"DEP005\", title: \"HTTP Registry URL\", severity: \"high\",\n description: \"Using HTTP (not HTTPS) for npm registry allows man-in-the-middle attacks on package downloads.\",\n fix: \"Use HTTPS for registry: registry=https://registry.npmjs.org/\",\n test: (content, filePath) => filePath.endsWith(\".npmrc\") && /registry\\s*=\\s*http:\\/\\//.test(content),\n },\n];\n\nfunction compareVersions(v1: string, v2: string): number {\n const parts1 = v1.replace(/^[^0-9]*/, \"\").split(\".\").map(Number);\n const parts2 = v2.replace(/^[^0-9]*/, \"\").split(\".\").map(Number);\n for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {\n const a = parts1[i] || 0;\n const b = parts2[i] || 0;\n if (a < b) return -1;\n if (a > b) return 1;\n }\n return 0;\n}\n\nfunction getSnippet(content: string, line: number): string {\n const lines = content.split(\"\\n\");\n const start = Math.max(0, line - 2);\n const end = Math.min(lines.length, line + 2);\n return lines.slice(start, end).map((l, i) => {\n const lineNum = start + i + 1;\n const prefix = lineNum === line ? \">\" : \" \";\n return `${prefix} ${String(lineNum).padStart(5)} | ${l}`;\n }).join(\"\\n\");\n}\n\nexport function scanDependencies(files: { path: string; content: string }[]): Finding[] {\n const findings: Finding[] = [];\n\n for (const { path: filePath, content } of files) {\n // npm package.json\n if (filePath.endsWith(\"package.json\") && !filePath.includes(\"node_modules\")) {\n try {\n const pkg = JSON.parse(content);\n const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };\n\n for (const [name, version] of Object.entries(allDeps)) {\n const vulns = KNOWN_VULN_NPM[name];\n if (!vulns) continue;\n\n const versionStr = String(version).replace(/^[\\^~>=<]*/g, \"\");\n for (const vuln of vulns) {\n if (compareVersions(versionStr, vuln.minSafe) < 0) {\n const line = content.split(\"\\n\").findIndex(l => l.includes(`\"${name}\"`)) + 1;\n findings.push({\n id: `${vuln.cve}-${filePath}:${line}`,\n rule: vuln.cve,\n severity: vuln.severity,\n title: vuln.title,\n description: vuln.description,\n file: filePath,\n line,\n snippet: getSnippet(content, line),\n fix: vuln.fix,\n category: \"Dependencies\",\n source: \"custom\",\n owasp: \"A06:2021\",\n cwe: \"CWE-1395\",\n });\n }\n }\n }\n } catch {\n // Invalid JSON — skip\n }\n }\n\n // Python requirements.txt\n if (filePath.match(/requirements.*\\.txt$/i)) {\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n const match = line.match(/^([a-zA-Z0-9_-]+)(?:[=<>!~]+(.+))?/);\n if (!match) continue;\n\n const name = match[1].toLowerCase();\n const version = match[2] || \"0.0.0\";\n const vulns = KNOWN_VULN_PYTHON[name];\n if (!vulns) continue;\n\n for (const vuln of vulns) {\n if (compareVersions(version, vuln.minSafe) < 0) {\n findings.push({\n id: `${vuln.cve}-${filePath}:${i + 1}`,\n rule: vuln.cve,\n severity: vuln.severity,\n title: vuln.title,\n description: vuln.description,\n file: filePath,\n line: i + 1,\n snippet: getSnippet(content, i + 1),\n fix: vuln.fix,\n category: \"Dependencies\",\n source: \"custom\",\n owasp: \"A06:2021\",\n cwe: \"CWE-1395\",\n });\n }\n }\n }\n }\n\n // Dependency pattern checks\n for (const pattern of DEP_PATTERNS) {\n if (pattern.test(content, filePath)) {\n findings.push({\n id: `${pattern.id}-${filePath}:1`,\n rule: pattern.id,\n severity: pattern.severity,\n title: pattern.title,\n description: pattern.description,\n file: filePath,\n line: 1,\n snippet: getSnippet(content, 1),\n fix: pattern.fix,\n category: \"Dependencies\",\n source: \"custom\",\n owasp: \"A06:2021\",\n cwe: \"CWE-1395\",\n });\n }\n }\n }\n\n return findings;\n}\n","/**\n * Secret Entropy Detection Scanner\n * Detects high-entropy strings that are likely secrets/keys/tokens\n * regardless of their naming pattern. Uses Shannon entropy calculation.\n */\n\nimport type { Finding } from \"../types.js\";\n\n// ────────────────────────────────────────────\n// Shannon Entropy Calculation\n// ────────────────────────────────────────────\n\nfunction shannonEntropy(str: string): number {\n const freq: Record<string, number> = {};\n for (const ch of str) {\n freq[ch] = (freq[ch] || 0) + 1;\n }\n const len = str.length;\n let entropy = 0;\n for (const count of Object.values(freq)) {\n const p = count / len;\n entropy -= p * Math.log2(p);\n }\n return entropy;\n}\n\n// ────────────────────────────────────────────\n// Known Safe Patterns (allowlist)\n// ────────────────────────────────────────────\n\nconst SAFE_PATTERNS = [\n // UUIDs\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,\n // Git commit hashes\n /^[0-9a-f]{40}$/i,\n // Short git hashes\n /^[0-9a-f]{7,8}$/i,\n // Hex colors\n /^#?[0-9a-fA-F]{3,8}$/,\n // Base64 encoded small data (< 20 chars)\n /^[A-Za-z0-9+/]{1,19}={0,2}$/,\n // Package versions\n /^\\d+\\.\\d+\\.\\d+/,\n // File hashes (integrity)\n /^sha\\d+-/i,\n // URLs without credentials\n /^https?:\\/\\/[^:@]*$/,\n // Date/time strings\n /^\\d{4}-\\d{2}-\\d{2}/,\n // Locale strings\n /^[a-z]{2}-[A-Z]{2}$/,\n // Common encodings\n /^utf-?8|ascii|latin|iso-8859/i,\n // MIME types\n /^(?:application|text|image|audio|video)\\//,\n // CSS/HTML values\n /^(?:inherit|none|auto|block|flex|grid|absolute|relative|fixed|px|em|rem|%)/,\n // Common placeholder/test values\n /^(?:test|example|sample|demo|placeholder|temp|tmp|foo|bar|baz|lorem|ipsum)/i,\n // DOCTYPE/DTD URLs\n /DTD|DOCTYPE|w3\\.org|apple\\.com\\/DTDs/i,\n // XML namespaces\n /xmlns|schema|xsd|xsi/i,\n];\n\n// File types that shouldn't be scanned for entropy\nconst SKIP_FILES = /\\.(css|scss|less|svg|md|txt|html?|xml|yml|yaml|toml|lock|map|woff2?|ttf|eot|ico|png|jpg|gif|webp)$/i;\n\n// Variable names that commonly hold non-secret long strings\nconst SAFE_VAR_NAMES = /(?:description|message|text|label|title|content|template|html|svg|css|style|class|query|mutation|schema|regex|pattern|format|placeholder|comment|url|path|route|endpoint|href|src|alt|name|type|version|encoding|charset)/i;\n\n// ────────────────────────────────────────────\n// Scanner\n// ────────────────────────────────────────────\n\ninterface EntropyMatch {\n value: string;\n line: number;\n entropy: number;\n context: string;\n}\n\nfunction getSnippet(content: string, line: number): string {\n const lines = content.split(\"\\n\");\n const start = Math.max(0, line - 2);\n const end = Math.min(lines.length, line + 2);\n return lines.slice(start, end).map((l, i) => {\n const lineNum = start + i + 1;\n const prefix = lineNum === line ? \">\" : \" \";\n return `${prefix} ${String(lineNum).padStart(5)} | ${l}`;\n }).join(\"\\n\");\n}\n\nexport function scanEntropy(files: { path: string; content: string }[]): Finding[] {\n const findings: Finding[] = [];\n\n for (const { path: filePath, content } of files) {\n // Skip non-source files\n if (SKIP_FILES.test(filePath)) continue;\n if (filePath.includes(\"node_modules\")) continue;\n if (filePath.includes(\".min.\")) continue;\n if (/(?:\\.test\\.|\\.spec\\.|__tests__|__mocks__|fixtures?\\/)/i.test(filePath)) continue;\n\n const lines = content.split(\"\\n\");\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n\n // Skip comment lines\n const trimmed = line.trimStart();\n if (trimmed.startsWith(\"//\") || trimmed.startsWith(\"#\") || trimmed.startsWith(\"*\") || trimmed.startsWith(\"/*\")) continue;\n\n // Find string assignments (quotes or backticks)\n const stringPattern = /(?:[:=]\\s*)([\"'`])([^\"'`\\n]{20,120})\\1/g;\n let match;\n\n while ((match = stringPattern.exec(line)) !== null) {\n const value = match[2];\n\n // Skip known safe patterns\n if (SAFE_PATTERNS.some(p => p.test(value))) continue;\n\n // Skip if the variable name suggests non-secret content\n const beforeAssign = line.substring(0, match.index);\n if (SAFE_VAR_NAMES.test(beforeAssign)) continue;\n\n // Skip if it looks like a URL without credentials\n if (/^https?:\\/\\/[^:@]*$/.test(value)) continue;\n\n // Skip if it contains spaces (likely a sentence/message)\n if ((value.match(/\\s/g) || []).length > 2) continue;\n\n // Calculate entropy\n const entropy = shannonEntropy(value);\n\n // High entropy thresholds:\n // - Hex strings (charset 16): entropy > 3.0\n // - Base64 strings (charset 64): entropy > 4.5\n // - General strings: entropy > 4.0\n const isHex = /^[0-9a-fA-F]+$/.test(value);\n const isBase64 = /^[A-Za-z0-9+/]+=*$/.test(value);\n\n let threshold = 4.0;\n if (isHex) threshold = 3.0;\n else if (isBase64) threshold = 4.5;\n\n // Minimum length for detection\n if (value.length < 20) continue;\n\n if (entropy >= threshold) {\n // Additional context checks to reduce false positives\n const varName = beforeAssign.match(/(\\w+)\\s*[:=]\\s*$/)?.[1] || \"\";\n\n // Boost confidence if variable name suggests secret\n const isLikelySecret = /(?:key|secret|token|password|passwd|pwd|api_?key|auth|credential|private|signing)/i.test(varName);\n\n // Only report if entropy is very high OR variable name suggests secret\n if (entropy >= 4.5 || isLikelySecret) {\n // Mask the value for display\n const masked = value.substring(0, 6) + \"...\" + value.substring(value.length - 4);\n\n findings.push({\n id: `ENTROPY-${filePath}:${i + 1}`,\n rule: \"ENTROPY\",\n severity: isLikelySecret ? \"critical\" : \"high\",\n title: \"High-Entropy String Detected (Possible Secret)\",\n description: `Found a high-entropy string (${entropy.toFixed(1)} bits) that may be a hardcoded secret or API key: \"${masked}\"`,\n file: filePath,\n line: i + 1,\n snippet: getSnippet(content, i + 1),\n fix: \"If this is a secret, move it to an environment variable. If it's not a secret (e.g., hash, encoded data), add it to .xploitscanignore.\",\n category: \"Secrets\",\n source: \"custom\",\n owasp: \"A02:2021\",\n cwe: \"CWE-798\",\n });\n }\n }\n }\n }\n }\n\n return findings;\n}\n","/**\n * Configuration File Deep Analyzer\n * Analyzes tsconfig, next.config, Dockerfile, GitHub Actions,\n * and other config files for security misconfigurations.\n */\n\nimport type { Finding } from \"../types.js\";\n\nfunction getSnippet(content: string, line: number): string {\n const lines = content.split(\"\\n\");\n const start = Math.max(0, line - 2);\n const end = Math.min(lines.length, line + 2);\n return lines.slice(start, end).map((l, i) => {\n const lineNum = start + i + 1;\n const prefix = lineNum === line ? \">\" : \" \";\n return `${prefix} ${String(lineNum).padStart(5)} | ${l}`;\n }).join(\"\\n\");\n}\n\ninterface ConfigCheck {\n id: string;\n title: string;\n severity: \"critical\" | \"high\" | \"medium\" | \"low\";\n category: string;\n description: string;\n fix: string;\n owasp: string;\n cwe: string;\n filePattern: RegExp;\n check: (content: string, filePath: string) => { line: number; snippet: string } | null;\n}\n\nconst CONFIG_CHECKS: ConfigCheck[] = [\n // ── TypeScript Config ──\n {\n id: \"CFG001\", title: \"TypeScript Strict Mode Disabled\", severity: \"medium\",\n category: \"Configuration\", description: \"TypeScript without strict mode misses type errors that can cause runtime bugs and security issues.\",\n fix: 'Enable strict mode in tsconfig.json: \"strict\": true',\n owasp: \"A05:2021\", cwe: \"CWE-710\",\n filePattern: /tsconfig\\.json$/,\n check(content) {\n try {\n if (/\"strict\"\\s*:\\s*false/.test(content)) {\n const line = content.split(\"\\n\").findIndex(l => /strict/.test(l)) + 1;\n return { line, snippet: getSnippet(content, line) };\n }\n if (!/\"strict\"\\s*:\\s*true/.test(content) && /\"compilerOptions\"/.test(content)) {\n return { line: 1, snippet: getSnippet(content, 1) };\n }\n } catch {}\n return null;\n },\n },\n {\n id: \"CFG002\", title: \"TypeScript allowJs Without checkJs\", severity: \"low\",\n category: \"Configuration\", description: \"allowJs without checkJs means JavaScript files bypass type checking entirely.\",\n fix: 'Add \"checkJs\": true alongside \"allowJs\": true in tsconfig.json.',\n owasp: \"A05:2021\", cwe: \"CWE-710\",\n filePattern: /tsconfig\\.json$/,\n check(content) {\n if (/\"allowJs\"\\s*:\\s*true/.test(content) && !/\"checkJs\"\\s*:\\s*true/.test(content)) {\n const line = content.split(\"\\n\").findIndex(l => /allowJs/.test(l)) + 1;\n return { line, snippet: getSnippet(content, line) };\n }\n return null;\n },\n },\n\n // ── Next.js Config ──\n {\n id: \"CFG003\", title: \"Next.js Missing Security Headers\", severity: \"medium\",\n category: \"Configuration\", description: \"Next.js app without security headers in next.config is missing important protections.\",\n fix: \"Add a headers() function to next.config.js with X-Frame-Options, X-Content-Type-Options, Referrer-Policy, and Content-Security-Policy.\",\n owasp: \"A05:2021\", cwe: \"CWE-693\",\n filePattern: /next\\.config\\.(js|mjs|ts)$/,\n check(content) {\n if (!/headers\\s*\\(/.test(content) && !/securityHeaders|security-headers/.test(content)) {\n return { line: 1, snippet: getSnippet(content, 1) };\n }\n return null;\n },\n },\n {\n id: \"CFG004\", title: \"Next.js Powered-By Header Not Disabled\", severity: \"low\",\n category: \"Configuration\", description: \"Next.js exposes X-Powered-By header by default, revealing your tech stack.\",\n fix: 'Add poweredByHeader: false to next.config.js.',\n owasp: \"A05:2021\", cwe: \"CWE-200\",\n filePattern: /next\\.config\\.(js|mjs|ts)$/,\n check(content) {\n if (!/poweredByHeader\\s*:\\s*false/.test(content)) {\n return { line: 1, snippet: getSnippet(content, 1) };\n }\n return null;\n },\n },\n\n // ── Dockerfile ──\n {\n id: \"CFG005\", title: \"Dockerfile Using Latest Tag\", severity: \"medium\",\n category: \"Configuration\", description: \"Using :latest tag in FROM makes builds non-reproducible and may pull vulnerable images.\",\n fix: \"Pin to a specific version: FROM node:20-alpine instead of FROM node:latest.\",\n owasp: \"A06:2021\", cwe: \"CWE-1395\",\n filePattern: /Dockerfile$/i,\n check(content) {\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n if (/^FROM\\s+\\S+:latest/i.test(lines[i].trim()) || /^FROM\\s+\\w+\\s*$/i.test(lines[i].trim())) {\n return { line: i + 1, snippet: getSnippet(content, i + 1) };\n }\n }\n return null;\n },\n },\n {\n id: \"CFG006\", title: \"Dockerfile Not Using Multi-Stage Build\", severity: \"low\",\n category: \"Configuration\", description: \"Single-stage Docker builds include build tools in the final image, increasing attack surface.\",\n fix: \"Use multi-stage builds: first stage for building, second stage (FROM alpine) for running.\",\n owasp: \"A05:2021\", cwe: \"CWE-1059\",\n filePattern: /Dockerfile$/i,\n check(content) {\n const fromCount = (content.match(/^FROM\\s/gmi) || []).length;\n if (fromCount <= 1 && content.includes(\"npm\") && content.length > 200) {\n return { line: 1, snippet: getSnippet(content, 1) };\n }\n return null;\n },\n },\n {\n id: \"CFG007\", title: \"Dockerfile Copies .env File\", severity: \"critical\",\n category: \"Configuration\", description: \"COPY that includes .env files bakes secrets into the Docker image layer.\",\n fix: \"Add .env to .dockerignore. Use build args or runtime env vars instead.\",\n owasp: \"A02:2021\", cwe: \"CWE-312\",\n filePattern: /Dockerfile$/i,\n check(content) {\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n if (/^COPY\\s.*\\.env\\b/i.test(lines[i].trim())) {\n return { line: i + 1, snippet: getSnippet(content, i + 1) };\n }\n }\n return null;\n },\n },\n\n // ── GitHub Actions ──\n {\n id: \"CFG008\", title: \"GitHub Actions with Broad Permissions\", severity: \"high\",\n category: \"Configuration\", description: \"GitHub Actions with write-all or broad permissions can be exploited if a dependency is compromised.\",\n fix: \"Use minimal permissions: permissions: { contents: read }. Only grant what's needed.\",\n owasp: \"A01:2021\", cwe: \"CWE-250\",\n filePattern: /\\.github\\/workflows\\/.*\\.(yml|yaml)$/,\n check(content) {\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n if (/permissions\\s*:\\s*write-all/i.test(lines[i])) {\n return { line: i + 1, snippet: getSnippet(content, i + 1) };\n }\n }\n return null;\n },\n },\n {\n id: \"CFG009\", title: \"GitHub Actions Using Unpinned Action\", severity: \"medium\",\n category: \"Configuration\", description: \"Using actions with @main or @master instead of a pinned SHA allows supply chain attacks.\",\n fix: \"Pin actions to a specific SHA: uses: actions/checkout@abc123... instead of @main.\",\n owasp: \"A06:2021\", cwe: \"CWE-1395\",\n filePattern: /\\.github\\/workflows\\/.*\\.(yml|yaml)$/,\n check(content) {\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n if (/uses:\\s*\\S+@(?:main|master|dev|latest)\\s*$/i.test(lines[i])) {\n return { line: i + 1, snippet: getSnippet(content, i + 1) };\n }\n }\n return null;\n },\n },\n\n // ── Vite Config ──\n {\n id: \"CFG010\", title: \"Vite Server Open to Network\", severity: \"medium\",\n category: \"Configuration\", description: \"Vite dev server with host: true exposes it to the entire network.\",\n fix: \"Remove host: true or use host: '127.0.0.1' for local-only access during development.\",\n owasp: \"A05:2021\", cwe: \"CWE-668\",\n filePattern: /vite\\.config\\.(js|ts|mjs)$/,\n check(content) {\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n if (/host\\s*:\\s*true/.test(lines[i]) || /host\\s*:\\s*['\"]0\\.0\\.0\\.0['\"]/.test(lines[i])) {\n return { line: i + 1, snippet: getSnippet(content, i + 1) };\n }\n }\n return null;\n },\n },\n\n // ── .npmrc ──\n {\n id: \"CFG011\", title: \"NPM Auth Token in .npmrc\", severity: \"critical\",\n category: \"Secrets\", description: \"NPM auth tokens in committed .npmrc files expose registry credentials.\",\n fix: \"Remove the token and add .npmrc to .gitignore. Use NPM_TOKEN env var instead.\",\n owasp: \"A02:2021\", cwe: \"CWE-798\",\n filePattern: /\\.npmrc$/,\n check(content) {\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n if (/_authToken|_auth=|\\/\\/registry.*:_password/.test(lines[i])) {\n return { line: i + 1, snippet: getSnippet(content, i + 1) };\n }\n }\n return null;\n },\n },\n\n // ── ESLint Config ──\n {\n id: \"CFG012\", title: \"Security ESLint Rules Disabled\", severity: \"medium\",\n category: \"Configuration\", description: \"Disabling security-related ESLint rules removes an important safety net.\",\n fix: \"Re-enable security rules or use eslint-plugin-security for automated checks.\",\n owasp: \"A05:2021\", cwe: \"CWE-710\",\n filePattern: /\\.eslint(rc)?(\\.(js|json|yml|yaml|cjs|mjs))?$/,\n check(content) {\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n if (/no-eval|no-implied-eval|no-new-func|no-script-url|security\\/detect/i.test(lines[i]) && /[\"']off[\"']|:\\s*0/.test(lines[i])) {\n return { line: i + 1, snippet: getSnippet(content, i + 1) };\n }\n }\n return null;\n },\n },\n];\n\nexport function scanConfigs(files: { path: string; content: string }[]): Finding[] {\n const findings: Finding[] = [];\n\n for (const { path: filePath, content } of files) {\n for (const check of CONFIG_CHECKS) {\n if (!check.filePattern.test(filePath)) continue;\n\n const result = check.check(content, filePath);\n if (result) {\n findings.push({\n id: `${check.id}-${filePath}:${result.line}`,\n rule: check.id,\n severity: check.severity,\n title: check.title,\n description: check.description,\n file: filePath,\n line: result.line,\n snippet: result.snippet,\n fix: check.fix,\n category: check.category,\n source: \"custom\",\n owasp: check.owasp,\n cwe: check.cwe,\n });\n }\n }\n }\n\n return findings;\n}\n","/**\n * Multi-File Analysis Scanner\n * Analyzes relationships between files to detect cross-file vulnerabilities\n * that single-file scanners miss.\n */\n\nimport type { Finding } from \"../types.js\";\n\nfunction getSnippet(content: string, line: number): string {\n const lines = content.split(\"\\n\");\n const start = Math.max(0, line - 2);\n const end = Math.min(lines.length, line + 2);\n return lines.slice(start, end).map((l, i) => {\n const lineNum = start + i + 1;\n const prefix = lineNum === line ? \">\" : \" \";\n return `${prefix} ${String(lineNum).padStart(5)} | ${l}`;\n }).join(\"\\n\");\n}\n\ninterface FileInfo {\n path: string;\n content: string;\n}\n\nexport function scanMultiFile(files: FileInfo[]): Finding[] {\n const findings: Finding[] = [];\n\n // Build indexes\n const fileMap = new Map<string, string>();\n for (const f of files) {\n fileMap.set(f.path, f.content);\n }\n\n // ── Check 1: API routes without middleware protection ──\n // If there's a middleware file that handles auth, routes are protected.\n // But if routes exist WITHOUT middleware, they're exposed.\n const hasGlobalMiddleware = files.some(f =>\n /middleware\\.(ts|js)$/.test(f.path) &&\n /(?:auth|session|clerk|nextauth|getToken)/i.test(f.content)\n );\n const hasAuthModule = files.some(f =>\n /(?:auth|middleware)\\.(ts|js)$/i.test(f.path) &&\n /(?:requireAuth|isAuthenticated|authenticate|verify)/i.test(f.content)\n );\n\n // Check API route files for auth\n for (const f of files) {\n if (!/(?:\\/api\\/|routes?\\/|controllers?\\/)/i.test(f.path)) continue;\n if (/middleware/i.test(f.path)) continue;\n\n // Skip health/status endpoints\n if (/(?:health|status|ping|ready|live)\\.(?:ts|js)/i.test(f.path)) continue;\n\n const hasLocalAuth = /(?:requireAuth|isAuthenticated|authenticate|verify|getAuth|getSession|getServerSession|withAuth|jwt\\.verify|clerk)/i.test(f.content);\n const hasAuthImport = /import.*(?:auth|session|middleware|verify|clerk)/i.test(f.content);\n\n if (!hasLocalAuth && !hasAuthImport && !hasGlobalMiddleware) {\n // Only flag if the file has actual route handlers\n if (/\\.(get|post|put|delete|patch)\\s*\\(|export\\s+(?:async\\s+)?function\\s+(?:GET|POST|PUT|DELETE|PATCH)/i.test(f.content)) {\n const line = f.content.split(\"\\n\").findIndex(l =>\n /\\.(get|post|put|delete|patch)\\s*\\(|export\\s+(?:async\\s+)?function\\s+(?:GET|POST|PUT|DELETE|PATCH)/i.test(l)\n ) + 1;\n findings.push({\n id: `MFA001-${f.path}:${line}`,\n rule: \"MFA001\",\n severity: \"high\",\n title: \"API Route Without Auth (Cross-File Check)\",\n description: \"This API route file has no authentication checks and no auth middleware was detected in the project.\",\n file: f.path,\n line,\n snippet: getSnippet(f.content, line),\n fix: \"Add authentication middleware or import your auth module. If using Next.js, create middleware.ts in your app root.\",\n category: \"Authentication\",\n source: \"custom\",\n owasp: \"A01:2021\",\n cwe: \"CWE-862\",\n });\n }\n }\n }\n\n // ── Check 2: .env file exists but .gitignore doesn't exclude it ──\n const hasEnvFile = files.some(f => /^\\.env$|\\/\\.env$/.test(f.path));\n const gitignore = files.find(f => f.path.endsWith(\".gitignore\"));\n if (hasEnvFile && gitignore) {\n if (!/^\\.env$/m.test(gitignore.content) && !/^\\*\\.env$/m.test(gitignore.content)) {\n findings.push({\n id: \"MFA002-.gitignore:1\",\n rule: \"MFA002\",\n severity: \"critical\",\n title: \".env File Not in .gitignore\",\n description: \"An .env file exists in the project but .gitignore doesn't exclude it. Secrets may be committed.\",\n file: \".gitignore\",\n line: 1,\n snippet: getSnippet(gitignore.content, 1),\n fix: \"Add .env to .gitignore: echo '.env' >> .gitignore\",\n category: \"Secrets\",\n source: \"custom\",\n owasp: \"A02:2021\",\n cwe: \"CWE-312\",\n });\n }\n }\n\n // ── Check 3: Database client without connection pooling ──\n const dbFiles = files.filter(f =>\n /(?:db|database|prisma|drizzle|sequelize|mongoose|knex)\\.(ts|js)$/i.test(f.path) ||\n /(?:createClient|createPool|createConnection|PrismaClient)/i.test(f.content)\n );\n for (const f of dbFiles) {\n // Check if DB client is created at module level (not in a function)\n if (/new PrismaClient/i.test(f.content)) {\n // Good pattern: globalThis.prisma = globalThis.prisma || new PrismaClient()\n if (!/globalThis|global\\./i.test(f.content)) {\n const line = f.content.split(\"\\n\").findIndex(l => /new PrismaClient/.test(l)) + 1;\n findings.push({\n id: `MFA003-${f.path}:${line}`,\n rule: \"MFA003\",\n severity: \"medium\",\n title: \"Database Client Not Cached (Connection Leak)\",\n description: \"Creating a new PrismaClient on every request leaks database connections. Use a singleton pattern.\",\n file: f.path,\n line,\n snippet: getSnippet(f.content, line),\n fix: \"Use singleton: globalThis.prisma = globalThis.prisma || new PrismaClient(). This prevents connection exhaustion in serverless.\",\n category: \"Configuration\",\n source: \"custom\",\n owasp: \"A05:2021\",\n cwe: \"CWE-400\",\n });\n }\n }\n }\n\n // ── Check 4: CORS origin mismatch ──\n // Check if CORS is configured but the origin doesn't match APP_URL or frontend URL\n for (const f of files) {\n if (!/(?:server|app|index|main)\\.(ts|js)$/i.test(f.path)) continue;\n const corsMatch = f.content.match(/origin\\s*:\\s*[\"'`](https?:\\/\\/[^\"'`]+)[\"'`]/);\n if (corsMatch) {\n const corsOrigin = corsMatch[1];\n if (corsOrigin.includes(\"localhost\") || corsOrigin.includes(\"127.0.0.1\")) {\n const line = f.content.split(\"\\n\").findIndex(l => l.includes(corsOrigin)) + 1;\n findings.push({\n id: `MFA004-${f.path}:${line}`,\n rule: \"MFA004\",\n severity: \"medium\",\n title: \"CORS Origin Set to Localhost\",\n description: \"CORS origin is hardcoded to localhost. This will block requests from your production frontend.\",\n file: f.path,\n line,\n snippet: getSnippet(f.content, line),\n fix: \"Use environment variable: origin: process.env.FRONTEND_URL || 'http://localhost:3000'\",\n category: \"Configuration\",\n source: \"custom\",\n owasp: \"A05:2021\",\n cwe: \"CWE-942\",\n });\n }\n }\n }\n\n // ── Check 5: Secret referenced but not in .env.example ──\n const envExample = files.find(f => /\\.env\\.example$|\\.env\\.sample$|\\.env\\.template$/.test(f.path));\n if (envExample) {\n const envVarsUsed = new Set<string>();\n for (const f of files) {\n if (/\\.(ts|js|tsx|jsx)$/i.test(f.path)) {\n const matches = f.content.matchAll(/process\\.env\\.([A-Z_][A-Z0-9_]*)/g);\n for (const m of matches) {\n envVarsUsed.add(m[1]);\n }\n }\n }\n const envVarsDocumented = new Set<string>();\n const exampleMatches = envExample.content.matchAll(/^([A-Z_][A-Z0-9_]*)=/gm);\n for (const m of exampleMatches) {\n envVarsDocumented.add(m[1]);\n }\n\n const undocumented = [...envVarsUsed].filter(v => !envVarsDocumented.has(v) && !v.startsWith(\"NODE_\") && v !== \"npm_\");\n if (undocumented.length > 0) {\n findings.push({\n id: `MFA005-${envExample.path}:1`,\n rule: \"MFA005\",\n severity: \"low\",\n title: \"Env Vars Used But Not in .env.example\",\n description: `These environment variables are used in code but missing from .env.example: ${undocumented.slice(0, 5).join(\", \")}${undocumented.length > 5 ? ` (+${undocumented.length - 5} more)` : \"\"}`,\n file: envExample.path,\n line: 1,\n snippet: getSnippet(envExample.content, 1),\n fix: \"Add missing variables to .env.example so team members know which env vars are needed.\",\n category: \"Configuration\",\n source: \"custom\",\n owasp: \"A05:2021\",\n cwe: \"CWE-1188\",\n });\n }\n }\n\n // ── Check 6: Frontend fetching HTTP API in production code ──\n for (const f of files) {\n if (!/\\.(tsx|jsx|ts|js)$/i.test(f.path)) continue;\n if (/(?:test|spec|mock|fixture)/i.test(f.path)) continue;\n\n const httpFetches = f.content.matchAll(/fetch\\s*\\(\\s*[\"'`](http:\\/\\/(?!localhost|127\\.0\\.0\\.1)[^\"'`]+)[\"'`]/g);\n for (const m of httpFetches) {\n const line = f.content.substring(0, m.index).split(\"\\n\").length;\n findings.push({\n id: `MFA006-${f.path}:${line}`,\n rule: \"MFA006\",\n severity: \"high\",\n title: \"Frontend Fetching Over HTTP (Not HTTPS)\",\n description: `Fetching from ${m[1].substring(0, 40)}... over HTTP exposes data to interception.`,\n file: f.path,\n line,\n snippet: getSnippet(f.content, line),\n fix: \"Use HTTPS for all API calls in production.\",\n category: \"Configuration\",\n source: \"custom\",\n owasp: \"A02:2021\",\n cwe: \"CWE-319\",\n });\n }\n }\n\n return findings;\n}\n","import chalk from \"chalk\";\nimport Table from \"cli-table3\";\nimport type { Finding, ScanResult, Severity } from \"../types.js\";\nimport { calculateGrade, detectFramework, type SecurityGrade } from \"../scanners/custom-rules.js\";\n\nconst SEVERITY_COLORS: Record<Severity, (text: string) => string> = {\n critical: chalk.bgRed.white.bold,\n high: chalk.red.bold,\n medium: chalk.yellow.bold,\n low: chalk.blue,\n info: chalk.gray,\n};\n\nconst SEVERITY_ICONS: Record<Severity, string> = {\n critical: \"!!!\",\n high: \" !! \",\n medium: \" ! \",\n low: \" - \",\n info: \" i \",\n};\n\nconst SEVERITY_ORDER: Record<Severity, number> = {\n critical: 0,\n high: 1,\n medium: 2,\n low: 3,\n info: 4,\n};\n\nconst GRADE_COLORS: Record<SecurityGrade, (text: string) => string> = {\n \"A+\": chalk.green.bold,\n \"A\": chalk.green.bold,\n \"B\": chalk.cyan.bold,\n \"C\": chalk.yellow.bold,\n \"D\": chalk.red.bold,\n \"F\": chalk.bgRed.white.bold,\n};\n\nexport function renderTerminalReport(result: ScanResult, files?: { path: string; content: string }[]): void {\n const { findings, filesScanned, duration } = result;\n\n // Header\n console.log(\"\");\n console.log(chalk.bold.cyan(\" xploitscan\") + chalk.gray(\" — security scan results\"));\n console.log(chalk.gray(\" \" + \"─\".repeat(50)));\n console.log(\"\");\n\n // Framework detection\n if (files && files.length > 0) {\n const frameworks = detectFramework(files);\n if (frameworks.length > 0 && frameworks[0] !== \"unknown\") {\n console.log(chalk.gray(\" Frameworks: \") + chalk.white(frameworks.join(\", \")));\n }\n }\n\n // Grade + Benchmark\n const GRADE_PERCENTILES: Record<string, number> = { \"A+\": 98, \"A\": 90, \"B\": 70, \"C\": 45, \"D\": 20, \"F\": 5 };\n const { grade, score, summary } = calculateGrade(findings, filesScanned);\n const gradeColor = GRADE_COLORS[grade];\n const percentile = GRADE_PERCENTILES[grade] ?? 50;\n console.log(chalk.gray(\" Security Grade: \") + gradeColor(` ${grade} `) + chalk.gray(` (${score}/100) — ${summary}`));\n console.log(chalk.gray(` Benchmark: More secure than ${percentile}% of projects scanned`));\n console.log(\"\");\n\n if (findings.length === 0) {\n console.log(chalk.green.bold(\" No vulnerabilities found!\"));\n console.log(chalk.gray(` Scanned ${filesScanned} files in ${(duration / 1000).toFixed(1)}s`));\n console.log(\"\");\n return;\n }\n\n // Sort by severity\n const sorted = [...findings].sort(\n (a, b) => SEVERITY_ORDER[a.severity] - SEVERITY_ORDER[b.severity],\n );\n\n // Summary table\n const counts: Record<Severity, number> = { critical: 0, high: 0, medium: 0, low: 0, info: 0 };\n for (const f of findings) counts[f.severity]++;\n\n const summaryParts: string[] = [];\n if (counts.critical > 0) summaryParts.push(chalk.bgRed.white.bold(` ${counts.critical} CRITICAL `));\n if (counts.high > 0) summaryParts.push(chalk.red.bold(`${counts.high} high`));\n if (counts.medium > 0) summaryParts.push(chalk.yellow.bold(`${counts.medium} medium`));\n if (counts.low > 0) summaryParts.push(chalk.blue(`${counts.low} low`));\n if (counts.info > 0) summaryParts.push(chalk.gray(`${counts.info} info`));\n\n console.log(` Found ${chalk.bold(findings.length.toString())} issues: ${summaryParts.join(chalk.gray(\" | \"))}`);\n console.log(chalk.gray(` Scanned ${filesScanned} files in ${(duration / 1000).toFixed(1)}s`));\n console.log(\"\");\n\n // Individual findings\n for (const finding of sorted) {\n const severityLabel = SEVERITY_COLORS[finding.severity](\n ` ${finding.severity.toUpperCase()} `,\n );\n const sourceLabel = finding.source === \"ai\"\n ? chalk.magenta(\" [AI] \")\n : finding.source === \"dependency\"\n ? chalk.cyan(\" [DEP] \")\n : finding.source === \"entropy\"\n ? chalk.yellow(\" [ENTROPY] \")\n : finding.source === \"config\"\n ? chalk.blue(\" [CFG] \")\n : finding.source === \"multi-file\"\n ? chalk.green(\" [CROSS-FILE] \")\n : chalk.gray(` [${finding.rule}] `);\n const confidenceLabel = finding.confidence\n ? chalk.gray(` (${finding.confidence} confidence)`)\n : \"\";\n\n const complianceTags = [\n finding.owasp ? chalk.yellow(`[${finding.owasp}]`) : \"\",\n finding.cwe ? chalk.blue(`[${finding.cwe}]`) : \"\",\n ].filter(Boolean).join(\" \");\n console.log(` ${severityLabel}${sourceLabel}${chalk.bold(finding.title)} ${complianceTags}${confidenceLabel}`);\n console.log(chalk.gray(` ${finding.file}:${finding.line}`));\n console.log(\"\");\n\n // Description\n console.log(chalk.white(` ${finding.description}`));\n console.log(\"\");\n\n // Code snippet\n if (finding.snippet) {\n const snippetLines = finding.snippet.split(\"\\n\");\n for (const line of snippetLines) {\n if (line.startsWith(\">\")) {\n console.log(chalk.red(` ${line}`));\n } else {\n console.log(chalk.gray(` ${line}`));\n }\n }\n console.log(\"\");\n }\n\n // Fix suggestion\n if (finding.fix) {\n console.log(chalk.green(` Fix: ${finding.fix}`));\n console.log(\"\");\n }\n\n console.log(chalk.gray(\" \" + \"─\".repeat(50)));\n console.log(\"\");\n }\n\n // OWASP Top 10 Summary\n const owaspFindings = findings.filter(f => f.owasp);\n if (owaspFindings.length > 0) {\n const owaspCats: Record<string, { name: string; count: number }> = {\n \"A01:2021\": { name: \"Broken Access Control\", count: 0 },\n \"A02:2021\": { name: \"Cryptographic Failures\", count: 0 },\n \"A03:2021\": { name: \"Injection\", count: 0 },\n \"A04:2021\": { name: \"Insecure Design\", count: 0 },\n \"A05:2021\": { name: \"Security Misconfiguration\", count: 0 },\n \"A06:2021\": { name: \"Vulnerable Components\", count: 0 },\n \"A07:2021\": { name: \"Auth Failures\", count: 0 },\n \"A08:2021\": { name: \"Data Integrity\", count: 0 },\n \"A09:2021\": { name: \"Logging Failures\", count: 0 },\n \"A10:2021\": { name: \"SSRF\", count: 0 },\n };\n for (const f of owaspFindings) {\n if (f.owasp && owaspCats[f.owasp]) owaspCats[f.owasp].count++;\n }\n console.log(chalk.bold(\" OWASP Top 10 Compliance\"));\n for (const [id, { name, count }] of Object.entries(owaspCats)) {\n const status = count > 0 ? chalk.red(`${count} issue${count > 1 ? \"s\" : \"\"}`) : chalk.green(\"PASS\");\n console.log(chalk.gray(` ${id} ${name}: `) + status);\n }\n console.log(\"\");\n }\n\n // Footer\n if (counts.critical > 0) {\n console.log(\n chalk.bgRed.white.bold(\" ACTION REQUIRED \") +\n chalk.red.bold(` ${counts.critical} critical issue${counts.critical > 1 ? \"s\" : \"\"} found. Fix these before deploying.`),\n );\n } else if (counts.high > 0) {\n console.log(\n chalk.yellow.bold(` Recommendation: Address the ${counts.high} high-severity issue${counts.high > 1 ? \"s\" : \"\"} before going to production.`),\n );\n }\n\n console.log(\"\");\n}\n","import type { ScanResult } from \"../types.js\";\n\nexport function renderJsonReport(result: ScanResult): void {\n console.log(JSON.stringify(result, null, 2));\n}\n","import type { Finding, ScanResult, Severity } from \"../types.js\";\n\nconst SEVERITY_TO_SARIF: Record<Severity, string> = {\n critical: \"error\",\n high: \"error\",\n medium: \"warning\",\n low: \"note\",\n info: \"none\",\n};\n\nconst SEVERITY_TO_LEVEL: Record<Severity, number> = {\n critical: 10.0,\n high: 8.0,\n medium: 5.0,\n low: 3.0,\n info: 1.0,\n};\n\ninterface SarifOutput {\n $schema: string;\n version: string;\n runs: Array<{\n tool: {\n driver: {\n name: string;\n version: string;\n informationUri: string;\n rules: Array<{\n id: string;\n shortDescription: { text: string };\n fullDescription: { text: string };\n defaultConfiguration: { level: string };\n properties: { security_severity: string; tags: string[] };\n }>;\n };\n };\n results: Array<{\n ruleId: string;\n ruleIndex: number;\n level: string;\n message: { text: string };\n locations: Array<{\n physicalLocation: {\n artifactLocation: { uri: string };\n region: {\n startLine: number;\n startColumn?: number;\n };\n };\n }>;\n fixes?: Array<{\n description: { text: string };\n }>;\n }>;\n }>;\n}\n\nexport function renderSarifReport(result: ScanResult): void {\n // Collect unique rules\n const ruleMap = new Map<string, Finding>();\n for (const f of result.findings) {\n if (!ruleMap.has(f.rule)) {\n ruleMap.set(f.rule, f);\n }\n }\n\n const rules = Array.from(ruleMap.entries()).map(([id, f]) => ({\n id,\n shortDescription: { text: f.title },\n fullDescription: { text: f.description },\n defaultConfiguration: { level: SEVERITY_TO_SARIF[f.severity] },\n properties: {\n security_severity: SEVERITY_TO_LEVEL[f.severity].toFixed(1),\n tags: [\"security\", f.category.toLowerCase().replace(/\\s+/g, \"-\")],\n },\n }));\n\n const ruleIndex = new Map(rules.map((r, i) => [r.id, i]));\n\n const sarif: SarifOutput = {\n $schema: \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json\",\n version: \"2.1.0\",\n runs: [\n {\n tool: {\n driver: {\n name: \"xploitscan\",\n version: \"0.1.0\",\n informationUri: \"https://github.com/bgage72590/xploitscan\",\n rules,\n },\n },\n results: result.findings.map((f) => {\n const entry: SarifOutput[\"runs\"][0][\"results\"][0] = {\n ruleId: f.rule,\n ruleIndex: ruleIndex.get(f.rule) ?? 0,\n level: SEVERITY_TO_SARIF[f.severity],\n message: {\n text: `${f.title}: ${f.description}`,\n },\n locations: [\n {\n physicalLocation: {\n artifactLocation: { uri: f.file },\n region: {\n startLine: f.line,\n ...(f.column ? { startColumn: f.column } : {}),\n },\n },\n },\n ],\n };\n\n if (f.fix) {\n entry.fixes = [{ description: { text: f.fix } }];\n }\n\n return entry;\n }),\n },\n ],\n };\n\n console.log(JSON.stringify(sarif, null, 2));\n}\n","import { createServer } from \"node:http\";\nimport { URL } from \"node:url\";\nimport { randomUUID } from \"node:crypto\";\nimport { execFile } from \"node:child_process\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { storeToken, clearToken, getStoredToken, syncUser } from \"../utils/api.js\";\n\nconst CLERK_PUBLISHABLE_KEY = process.env.CLERK_PUBLISHABLE_KEY ?? \"\";\n\n/**\n * Opens a browser-based login flow.\n * 1. Starts a local HTTP server on a random port\n * 2. Opens the Clerk sign-in page with redirect back to local server\n * 3. Receives the token via redirect callback\n * 4. Stores the token locally\n */\nexport async function loginCommand(): Promise<void> {\n const existing = getStoredToken();\n if (existing) {\n console.log(chalk.yellow(`Already logged in as ${existing.email}`));\n console.log(chalk.gray(\"Run `xploitscan auth logout` first to switch accounts.\"));\n return;\n }\n\n const spinner = ora(\"Waiting for browser login...\").start();\n\n // Start local callback server\n const { token, email, userId } = await waitForBrowserLogin();\n\n spinner.text = \"Syncing account...\";\n\n // Store token\n storeToken({\n token,\n userId,\n email,\n expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000, // 7 days\n });\n\n // Sync user with API\n const user = await syncUser();\n spinner.stop();\n\n console.log(chalk.green(`Logged in as ${email}`));\n if (user) {\n console.log(chalk.gray(`Plan: ${user.plan}`));\n }\n}\n\nexport async function logoutCommand(): Promise<void> {\n const existing = getStoredToken();\n if (!existing) {\n console.log(chalk.gray(\"Not logged in.\"));\n return;\n }\n\n clearToken();\n console.log(chalk.green(\"Logged out successfully.\"));\n}\n\nexport async function whoamiCommand(): Promise<void> {\n const token = getStoredToken();\n if (!token) {\n console.log(chalk.gray(\"Not logged in. Run `xploitscan auth login` to authenticate.\"));\n return;\n }\n\n console.log(chalk.cyan(`Email: ${token.email}`));\n console.log(chalk.gray(`User ID: ${token.userId}`));\n\n const user = await syncUser();\n if (user) {\n const planBadge = user.plan === \"pro\"\n ? chalk.bgGreen.black(\" PRO \")\n : chalk.bgGray.white(\" FREE \");\n console.log(`Plan: ${planBadge}`);\n }\n}\n\nasync function waitForBrowserLogin(): Promise<{\n token: string;\n email: string;\n userId: string;\n}> {\n return new Promise((resolve, reject) => {\n const expectedState = randomUUID();\n\n const server = createServer((req, res) => {\n if (!req.url) {\n res.writeHead(400);\n res.end(\"Bad request\");\n return;\n }\n\n const url = new URL(req.url, `http://localhost`);\n\n if (url.pathname === \"/callback\") {\n const token = url.searchParams.get(\"token\");\n const email = url.searchParams.get(\"email\");\n const userId = url.searchParams.get(\"user_id\");\n const state = url.searchParams.get(\"state\");\n\n if (!state || state !== expectedState) {\n res.writeHead(403);\n res.end(\"Invalid state parameter — possible CSRF attack.\");\n return;\n }\n\n if (token && email && userId) {\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(`\n <html>\n <body style=\"font-family: system-ui; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #0a0a0f; color: #e0e0e0;\">\n <div style=\"text-align: center;\">\n <h1 style=\"color: #00d4ff;\">xploitscan</h1>\n <p style=\"color: #4ade80; font-size: 1.2rem;\">Login successful!</p>\n <p style=\"color: #888;\">You can close this tab and return to your terminal.</p>\n </div>\n </body>\n </html>\n `);\n\n server.close();\n resolve({ token, email, userId });\n } else {\n res.writeHead(400);\n res.end(\"Missing parameters\");\n }\n } else if (url.pathname === \"/login\") {\n // Serve a simple login page that redirects to Clerk\n const callbackUrl = `http://localhost:${(server.address() as { port: number }).port}/callback`;\n\n // Development-only bypass — requires both env vars to be explicitly set\n if (process.env.NODE_ENV === \"development\" && process.env.XPLOITSCAN_DEV_AUTH === \"true\") {\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(`\n <html>\n <body style=\"font-family: system-ui; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #0a0a0f; color: #e0e0e0;\">\n <div style=\"text-align: center;\">\n <h1 style=\"color: #00d4ff;\">xploitscan</h1>\n <p>Redirecting to login (dev mode)...</p>\n <script>\n const params = new URLSearchParams({\n token: 'dev_token_' + Date.now(),\n email: 'dev@xploitscan.com',\n user_id: 'user_dev_' + Date.now(),\n state: '${expectedState}'\n });\n setTimeout(() => {\n window.location.href = '/callback?' + params.toString();\n }, 1000);\n </script>\n </div>\n </body>\n </html>\n `);\n } else {\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(`\n <html>\n <body style=\"font-family: system-ui; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #0a0a0f; color: #e0e0e0;\">\n <div style=\"text-align: center;\">\n <h1 style=\"color: #00d4ff;\">xploitscan</h1>\n <p>Redirecting to login...</p>\n <p style=\"color: #888; font-size: 0.85rem;\">If not redirected, <a href=\"#\" style=\"color: #00d4ff;\">click here</a>.</p>\n </div>\n </body>\n </html>\n `);\n }\n } else {\n res.writeHead(302, { Location: \"/login\" });\n res.end();\n }\n });\n\n // Listen on random available port\n server.listen(0, \"127.0.0.1\", () => {\n const addr = server.address() as { port: number };\n const loginUrl = `http://localhost:${addr.port}/login`;\n\n console.log(chalk.cyan(`\\nOpen this URL in your browser to log in:`));\n console.log(chalk.bold.underline(loginUrl));\n console.log(\"\");\n\n // Try to open browser automatically\n const openCmd = process.platform === \"darwin\" ? \"open\" : process.platform === \"win32\" ? \"start\" : \"xdg-open\";\n execFile(openCmd, [loginUrl], () => {});\n });\n\n // Timeout after 5 minutes\n setTimeout(() => {\n server.close();\n reject(new Error(\"Login timed out. Please try again.\"));\n }, 5 * 60 * 1000);\n });\n}\n"],"mappings":"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C3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,WAAW;AAAA,EAC5C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,WAAW;AAAA,EAC5C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EA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","names":["resolve","join","chalk","readFileSync","join","rm","existsSync","join","resolve","execFile","readFile","mkdtemp","rm","existsSync","join","tmpdir","resolve","execFile","mkdtemp","join","tmpdir","existsSync","readFile","rm","lines","getSnippet","getSnippet","getSnippet","getSnippet","resolve","chalk","join","execFile","chalk","ora","chalk","ora","resolve","execFile","getStoredToken","chalk","execFile"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/scan.ts","../src/utils/files.ts","../src/utils/config.ts","../src/scanners/custom-rules.ts","../src/scanners/semgrep.ts","../src/scanners/gitleaks.ts","../src/scanners/ai-analyzer.ts","../src/scanners/ast-analyzer.ts","../src/scanners/dependency-scanner.ts","../src/scanners/entropy-scanner.ts","../src/scanners/config-analyzer.ts","../src/scanners/multi-file-analyzer.ts","../src/reporters/terminal.ts","../src/reporters/json.ts","../src/reporters/sarif.ts","../src/commands/auth.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { scanCommand } from \"./commands/scan.js\";\nimport { loginCommand, logoutCommand, whoamiCommand } from \"./commands/auth.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"xploitscan\")\n .description(\n \"AI security scanner for vibe-coded apps. Find vulnerabilities before attackers do.\",\n )\n .version(\"0.3.0\");\n\nprogram\n .command(\"scan\")\n .description(\"Scan a directory for security vulnerabilities\")\n .argument(\"[directory]\", \"Directory to scan\", \".\")\n .option(\"--no-ai\", \"Skip AI-powered analysis\")\n .option(\"-f, --format <format>\", \"Output format: terminal, json, sarif\", \"terminal\")\n .option(\"-v, --verbose\", \"Show detailed output\", false)\n .option(\"--diff [base]\", \"Scan only files changed vs base branch (default: main)\")\n .option(\"-w, --watch\", \"Watch for file changes and re-scan automatically\", false)\n .action(async (directory: string, opts: { ai: boolean; format: string; verbose: boolean; diff?: string | boolean; watch: boolean }) => {\n await scanCommand(directory, {\n directory,\n aiAnalysis: opts.ai,\n format: opts.format as \"terminal\" | \"json\" | \"sarif\",\n verbose: opts.verbose,\n diff: opts.diff,\n watch: opts.watch,\n });\n });\n\n// Auth commands\nconst auth = program\n .command(\"auth\")\n .description(\"Manage authentication\");\n\nauth\n .command(\"login\")\n .description(\"Log in to your XploitScan account\")\n .action(loginCommand);\n\nauth\n .command(\"logout\")\n .description(\"Log out of your XploitScan account\")\n .action(logoutCommand);\n\nauth\n .command(\"whoami\")\n .description(\"Show current logged-in user\")\n .action(whoamiCommand);\n\n// Upgrade command (shortcut)\nprogram\n .command(\"upgrade\")\n .description(\"Upgrade to XploitScan Pro for unlimited scans\")\n .action(async () => {\n const { getStoredToken, getCheckoutUrl } = await import(\"./utils/api.js\");\n const chalk = (await import(\"chalk\")).default;\n\n const token = getStoredToken();\n if (!token) {\n console.log(chalk.yellow(\"Please log in first: xploitscan auth login\"));\n return;\n }\n\n console.log(chalk.cyan(\"Creating checkout session...\"));\n const url = await getCheckoutUrl();\n if (url) {\n console.log(chalk.green(`\\nOpen this URL to upgrade:`));\n console.log(chalk.bold.underline(url));\n const { execFile } = require(\"node:child_process\");\n const openCmd = process.platform === \"darwin\" ? \"open\" : process.platform === \"win32\" ? \"start\" : \"xdg-open\";\n execFile(openCmd, [url], () => {});\n } else {\n console.log(chalk.red(\"Failed to create checkout session. Please try again.\"));\n }\n });\n\nprogram.parse();\n","import { resolve, join, relative } from \"node:path\";\nimport { watch as fsWatch } from \"node:fs\";\nimport ora from \"ora\";\nimport chalk from \"chalk\";\nimport type { Finding, ScanOptions, ScanResult } from \"../types.js\";\nimport { collectFiles, readFileContents } from \"../utils/files.js\";\nimport { loadConfig } from \"../utils/config.js\";\nimport { runCustomRules } from \"../scanners/custom-rules.js\";\nimport { runSemgrep } from \"../scanners/semgrep.js\";\nimport { runGitleaks } from \"../scanners/gitleaks.js\";\nimport { analyzeWithAI } from \"../scanners/ai-analyzer.js\";\nimport { buildASTContext } from \"../scanners/ast-analyzer.js\";\nimport { scanDependencies } from \"../scanners/dependency-scanner.js\";\nimport { scanEntropy } from \"../scanners/entropy-scanner.js\";\nimport { scanConfigs } from \"../scanners/config-analyzer.js\";\nimport { scanMultiFile } from \"../scanners/multi-file-analyzer.js\";\nimport { renderTerminalReport } from \"../reporters/terminal.js\";\nimport { renderJsonReport } from \"../reporters/json.js\";\nimport { renderSarifReport } from \"../reporters/sarif.js\";\nimport { checkUsage, incrementUsage, uploadScanResults, isAuthenticated } from \"../utils/api.js\";\n\nexport async function scanCommand(\n directory: string,\n options: Partial<ScanOptions>,\n): Promise<void> {\n const dir = resolve(directory || \".\");\n const format = options.format ?? \"terminal\";\n const verbose = options.verbose ?? false;\n const startTime = Date.now();\n\n // Load config\n const config = await loadConfig(dir);\n const useAI = (options.aiAnalysis ?? config.ai ?? true) && !!process.env.ANTHROPIC_API_KEY;\n\n const isSilent = format !== \"terminal\";\n\n // Step 0: Check usage limits (if authenticated)\n if (isAuthenticated()) {\n const usage = await checkUsage();\n if (!usage.allowed) {\n console.log(chalk.red(\"\\nDaily scan limit reached (3/3 scans used).\"));\n console.log(chalk.yellow(\"Upgrade to Pro for unlimited scans: \") + chalk.bold(\"xploitscan upgrade\"));\n console.log(chalk.gray(`Resets tomorrow. Plan: ${usage.plan}\\n`));\n process.exitCode = 1;\n return;\n }\n if (usage.plan === \"free\" && usage.remaining > 0 && usage.remaining <= 2 && !isSilent) {\n console.log(chalk.gray(` ${usage.remaining} free scan${usage.remaining === 1 ? \"\" : \"s\"} remaining today\\n`));\n }\n }\n\n // Step 1: Collect files\n const spinner = ora({\n text: \"Scanning files...\",\n color: \"cyan\",\n isSilent,\n }).start();\n\n let files: string[];\n try {\n files = await collectFiles(dir);\n } catch (error) {\n spinner.fail(\"Failed to scan directory\");\n console.error(chalk.red(`Error: ${error instanceof Error ? error.message : error}`));\n process.exit(1);\n }\n\n // Diff mode: filter to only changed files\n if (options.diff) {\n const base = typeof options.diff === \"string\" ? options.diff : \"main\";\n try {\n const { execSync } = await import(\"node:child_process\");\n const changedFiles = execSync(`git diff --name-only ${base}`, { cwd: dir, encoding: \"utf-8\" })\n .trim().split(\"\\n\").filter(Boolean);\n files = files.filter(f => changedFiles.some(cf => f.endsWith(cf) || cf.endsWith(f)));\n if (!isSilent) {\n spinner.info(chalk.gray(` Diff mode: scanning ${files.length} changed files vs ${base}`));\n }\n } catch {\n spinner.warn(\"Could not run git diff — scanning all files\");\n }\n }\n\n if (files.length === 0) {\n spinner.warn(\"No source files found in this directory\");\n return;\n }\n\n spinner.text = `Found ${files.length} files. Running security rules...`;\n\n // Step 2: Run all static scanners in parallel\n const allFindings: Finding[] = [];\n\n // 2a: Custom rules with AST context (always runs, instant)\n const fileContentsForAnalysis: { path: string; content: string }[] = [];\n for (const filePath of files) {\n const content = readFileContents(dir, filePath);\n if (!content) continue;\n fileContentsForAnalysis.push({ path: filePath, content });\n\n // Build AST context for false positive reduction\n const astCtx = buildASTContext(content, filePath);\n\n // Skip scanner files scanning themselves\n if (astCtx.isScannerFile) continue;\n\n // Run custom rules with AST-stripped content for comment-heavy files\n const findings = runCustomRules(content, filePath, config.disableRules);\n\n // Add confidence scores based on AST context\n for (const f of findings) {\n if (astCtx.isTestFile) {\n f.confidence = \"low\";\n } else if (astCtx.isConfigFile) {\n f.confidence = \"medium\";\n } else {\n f.confidence = \"high\";\n }\n }\n\n allFindings.push(...findings);\n }\n\n const customCount = allFindings.length;\n if (verbose && customCount > 0) {\n spinner.info(`Custom rules found ${customCount} issues`);\n }\n\n // 2b: Dependency vulnerability scanning\n spinner.text = \"Scanning dependencies...\";\n const depFindings = scanDependencies(fileContentsForAnalysis);\n for (const f of depFindings) { f.confidence = \"high\"; }\n allFindings.push(...depFindings);\n if (verbose && depFindings.length > 0) {\n spinner.info(`Dependency scanner found ${depFindings.length} issues`);\n }\n\n // 2c: Entropy-based secret detection\n spinner.text = \"Scanning for high-entropy secrets...\";\n const entropyFindings = scanEntropy(fileContentsForAnalysis);\n for (const f of entropyFindings) { f.confidence = \"medium\"; }\n allFindings.push(...entropyFindings);\n if (verbose && entropyFindings.length > 0) {\n spinner.info(`Entropy scanner found ${entropyFindings.length} potential secrets`);\n }\n\n // 2d: Configuration file deep analysis\n spinner.text = \"Analyzing configuration files...\";\n const configFindings = scanConfigs(fileContentsForAnalysis);\n for (const f of configFindings) { f.confidence = \"high\"; }\n allFindings.push(...configFindings);\n if (verbose && configFindings.length > 0) {\n spinner.info(`Config analyzer found ${configFindings.length} issues`);\n }\n\n // 2e: Multi-file cross-reference analysis\n spinner.text = \"Running cross-file analysis...\";\n const multiFileFindings = scanMultiFile(fileContentsForAnalysis);\n for (const f of multiFileFindings) { f.confidence = \"medium\"; }\n allFindings.push(...multiFileFindings);\n if (verbose && multiFileFindings.length > 0) {\n spinner.info(`Multi-file analyzer found ${multiFileFindings.length} issues`);\n }\n\n // 2f: Semgrep + Gitleaks (run in parallel, gracefully skip if not installed)\n spinner.text = \"Running external scanners...\";\n spinner.color = \"yellow\";\n\n // Resolve custom rules directory (shipped with xploitscan)\n const rulesDir = resolve(join(import.meta.dirname, \"../../rules\"));\n const fallbackRulesDir = resolve(join(dir, \"../rules\"));\n\n const [semgrepResult, gitleaksResult] = await Promise.allSettled([\n runSemgrep(dir, rulesDir).catch(() => runSemgrep(dir, fallbackRulesDir)).catch(() => ({ findings: [] as Finding[], available: false })),\n runGitleaks(dir).catch(() => ({ findings: [] as Finding[], available: false })),\n ]);\n\n const semgrep = semgrepResult.status === \"fulfilled\" ? semgrepResult.value : { findings: [], available: false };\n const gitleaks = gitleaksResult.status === \"fulfilled\" ? gitleaksResult.value : { findings: [], available: false };\n\n allFindings.push(...semgrep.findings);\n allFindings.push(...gitleaks.findings);\n\n if (verbose) {\n if (semgrep.available) {\n spinner.info(`Semgrep found ${semgrep.findings.length} issues`);\n } else {\n spinner.info(chalk.gray(\"Semgrep not installed — install with: pip install semgrep\"));\n }\n if (gitleaks.available) {\n spinner.info(`Gitleaks found ${gitleaks.findings.length} issues`);\n } else {\n spinner.info(chalk.gray(\"Gitleaks not installed — install with: brew install gitleaks\"));\n }\n }\n\n // Show install hints for missing tools (non-verbose, terminal only)\n if (!isSilent && !verbose) {\n const missing: string[] = [];\n if (!semgrep.available) missing.push(\"semgrep (pip install semgrep)\");\n if (!gitleaks.available) missing.push(\"gitleaks (brew install gitleaks)\");\n if (missing.length > 0) {\n spinner.info(chalk.gray(`Optional: install ${missing.join(\" and \")} for deeper scanning`));\n }\n }\n\n const staticCount = allFindings.length;\n spinner.text = `Static analysis found ${staticCount} issue${staticCount !== 1 ? \"s\" : \"\"}`;\n\n // Step 3: AI analysis (if enabled)\n if (useAI) {\n spinner.text = \"Running AI analysis...\";\n spinner.color = \"magenta\";\n\n try {\n const priorityFiles = files\n .map((path) => ({\n path,\n content: readFileContents(dir, path) ?? \"\",\n }))\n .filter((f) => f.content.length > 0 && f.content.length < 30_000)\n .filter((f) => {\n const isHighPriority =\n /(?:api|server|route|auth|middleware|webhook|payment|stripe|supabase)/i.test(f.path) ||\n allFindings.some((finding) => finding.file === f.path) ||\n /(?:query|execute|fetch|prisma|drizzle|mongoose)/i.test(f.content);\n return isHighPriority;\n })\n .slice(0, 20);\n\n if (priorityFiles.length > 0) {\n const aiFindings = await analyzeWithAI(priorityFiles, allFindings);\n allFindings.push(...aiFindings);\n\n if (verbose && aiFindings.length > 0) {\n spinner.info(`AI analysis found ${aiFindings.length} additional issues`);\n }\n }\n } catch (error) {\n if (error instanceof Error) {\n spinner.warn(`AI analysis skipped: ${error.message}`);\n }\n }\n } else if (!process.env.ANTHROPIC_API_KEY && !isSilent) {\n spinner.info(\n chalk.gray(\"Tip: Set ANTHROPIC_API_KEY for AI-powered contextual analysis\"),\n );\n }\n\n spinner.stop();\n\n // Step 4: Deduplicate findings (same file + line + similar rule)\n const seen = new Set<string>();\n const dedupedFindings = allFindings.filter((f) => {\n // Normalize: group by file:line and a simplified rule key\n const ruleKey = f.source === \"gitleaks\" ? `secret:${f.file}:${f.line}` : `${f.rule}:${f.file}:${f.line}`;\n if (seen.has(ruleKey)) return false;\n seen.add(ruleKey);\n return true;\n });\n\n // Step 5: Render results\n const result: ScanResult = {\n findings: dedupedFindings,\n filesScanned: files.length,\n duration: Date.now() - startTime,\n timestamp: new Date().toISOString(),\n directory: dir,\n };\n\n switch (format) {\n case \"json\":\n renderJsonReport(result);\n break;\n case \"sarif\":\n renderSarifReport(result);\n break;\n default:\n renderTerminalReport(result, fileContentsForAnalysis);\n break;\n }\n\n // Step 6: Upload results and increment usage (if authenticated)\n if (isAuthenticated()) {\n await Promise.allSettled([\n incrementUsage(),\n uploadScanResults({\n directory: dir,\n filesScanned: files.length,\n findings: dedupedFindings,\n duration: Date.now() - startTime,\n }),\n ]);\n }\n\n // Exit with error code if critical/high findings exist\n const hasCritical = dedupedFindings.some(\n (f) => f.severity === \"critical\" || f.severity === \"high\",\n );\n if (hasCritical) {\n process.exitCode = 1;\n }\n\n // Step 7: Watch mode\n if (options.watch) {\n const watchExclude = new Set([\"node_modules\", \".git\", \"dist\", \"build\", \".next\"]);\n const debounceMs = 500;\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n let isScanning = false;\n\n console.log(chalk.cyan(\"\\nWatching for changes... (press Ctrl+C to stop)\"));\n\n fsWatch(dir, { recursive: true }, (_event, filename) => {\n if (!filename) return;\n\n // Skip excluded directories\n const parts = filename.split(\"/\");\n if (parts.some((p) => watchExclude.has(p))) return;\n\n console.log(chalk.gray(`File changed: ${filename}`));\n\n if (debounceTimer) clearTimeout(debounceTimer);\n\n debounceTimer = setTimeout(async () => {\n if (isScanning) return;\n isScanning = true;\n\n console.log(chalk.cyan(\"\\nRe-scanning...\\n\"));\n try {\n await scanCommand(directory, {\n ...options,\n watch: false, // prevent recursive watch\n });\n } catch (error) {\n console.error(chalk.red(`Re-scan error: ${error instanceof Error ? error.message : error}`));\n } finally {\n isScanning = false;\n console.log(chalk.cyan(\"\\nWatching for changes... (press Ctrl+C to stop)\"));\n }\n }, debounceMs);\n });\n\n // Keep the process alive\n await new Promise(() => {});\n }\n}\n","import fg from \"fast-glob\";\nimport ignore from \"ignore\";\nimport { readFileSync, existsSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\n\nconst SOURCE_EXTENSIONS = [\n \"js\", \"jsx\", \"ts\", \"tsx\", \"mjs\", \"cjs\",\n \"vue\", \"svelte\", \"astro\",\n \"py\", \"rb\", \"go\", \"rs\", \"java\", \"php\",\n \"swift\", \"kt\", \"kts\", \"dart\", \"cs\",\n \"c\", \"cpp\", \"h\",\n \"sh\", \"bash\", \"zsh\",\n \"env\", \"yaml\", \"yml\", \"toml\", \"json\", \"xml\",\n \"html\", \"htm\", \"sql\",\n \"properties\", \"ini\", \"cfg\", \"conf\",\n \"tf\", \"hcl\", \"dockerfile\",\n \"erb\", \"jinja\", \"j2\",\n \"gradle\",\n \"r\", \"lua\", \"pl\", \"pm\", \"ex\", \"exs\",\n \"ipynb\", \"md\",\n \"prisma\", \"plist\", \"pbxproj\", \"entitlements\", \"rules\", \"csv\",\n];\n\nconst SOURCE_FILENAMES = [\n \"Dockerfile\", \"Makefile\", \"Gemfile\", \"Rakefile\",\n \"package.json\", \"Cargo.toml\", \"go.mod\", \"requirements.txt\", \"Pipfile\",\n \"next.config.js\", \"next.config.mjs\", \"next.config.ts\", \"vercel.json\",\n \"firebase.json\", \".firebaserc\", \"firestore.rules\",\n \"app.json\", \"app.config.js\", \"eas.json\",\n \"wrangler.toml\", \"netlify.toml\",\n \"drizzle.config.ts\", \"drizzle.config.js\",\n \"Procfile\", \"Caddyfile\", \"nginx.conf\",\n \"AndroidManifest.xml\",\n];\n\nconst ALWAYS_IGNORE = [\n \"node_modules\",\n \".git\",\n \"dist\",\n \"build\",\n \".next\",\n \".nuxt\",\n \".svelte-kit\",\n \"vendor\",\n \"__pycache__\",\n \".venv\",\n \"venv\",\n \"coverage\",\n \".turbo\",\n \"*.min.js\",\n \"*.min.css\",\n \"*.map\",\n \"package-lock.json\",\n \"pnpm-lock.yaml\",\n \"yarn.lock\",\n];\n\nexport async function collectFiles(directory: string): Promise<string[]> {\n const ig = ignore.default();\n\n // Load .gitignore if present\n const gitignorePath = join(directory, \".gitignore\");\n if (existsSync(gitignorePath)) {\n const gitignoreContent = readFileSync(gitignorePath, \"utf-8\");\n ig.add(gitignoreContent);\n }\n\n // Load .xploitscanignore if present\n const xploitscanIgnorePath = join(directory, \".xploitscanignore\");\n if (existsSync(xploitscanIgnorePath)) {\n const xploitscanIgnoreContent = readFileSync(xploitscanIgnorePath, \"utf-8\");\n ig.add(xploitscanIgnoreContent);\n }\n\n // Always ignore these\n ig.add(ALWAYS_IGNORE);\n\n const patterns = SOURCE_EXTENSIONS.map((ext) => `**/*.${ext}`);\n // Also grab dotfiles like .env, .env.local, etc.\n patterns.push(\"**/.env*\");\n // Also grab files matched by name (Dockerfile, Makefile, etc.)\n for (const name of SOURCE_FILENAMES) {\n patterns.push(`**/${name}`);\n }\n\n const files = await fg(patterns, {\n cwd: directory,\n absolute: false,\n dot: true,\n onlyFiles: true,\n ignore: ALWAYS_IGNORE.map((p) => `**/${p}`),\n });\n\n // Apply .gitignore filtering\n return files.filter((file) => !ig.ignores(file));\n}\n\nexport function readFileContents(\n directory: string,\n filePath: string,\n): string | null {\n try {\n const fullPath = resolve(join(directory, filePath));\n if (!fullPath.startsWith(resolve(directory))) {\n throw new Error(\"Path traversal detected\");\n }\n return readFileSync(fullPath, \"utf-8\");\n } catch {\n return null;\n }\n}\n\nexport function getSnippet(\n content: string,\n line: number,\n contextLines = 2,\n): string {\n const lines = content.split(\"\\n\");\n const start = Math.max(0, line - 1 - contextLines);\n const end = Math.min(lines.length, line + contextLines);\n\n return lines\n .slice(start, end)\n .map((l, i) => {\n const lineNum = start + i + 1;\n const marker = lineNum === line ? \">\" : \" \";\n return `${marker} ${lineNum.toString().padStart(4)} | ${l}`;\n })\n .join(\"\\n\");\n}\n","import { cosmiconfig } from \"cosmiconfig\";\nimport { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport interface XploitScanRcConfig {\n rules?: {\n disable?: string[];\n severityOverride?: Record<string, string>;\n };\n scan?: {\n exclude?: string[];\n maxFileSize?: number;\n extensions?: string[];\n };\n output?: {\n format?: \"terminal\" | \"json\" | \"sarif\";\n verbose?: boolean;\n };\n watch?: {\n debounce?: number;\n exclude?: string[];\n };\n}\n\nexport interface XploitScanConfig {\n /** Glob patterns to exclude from scanning */\n exclude?: string[];\n /** Enable/disable AI analysis (requires ANTHROPIC_API_KEY) */\n ai?: boolean;\n /** Severity threshold to report: only show findings at or above this level */\n severity?: \"critical\" | \"high\" | \"medium\" | \"low\" | \"info\";\n /** Custom rules to disable by ID */\n disableRules?: string[];\n /** Severity overrides by rule ID */\n severityOverride?: Record<string, string>;\n /** Max file size in bytes */\n maxFileSize?: number;\n /** Additional file extensions to scan */\n extensions?: string[];\n /** Output format */\n format?: \"terminal\" | \"json\" | \"sarif\";\n /** Verbose output */\n verbose?: boolean;\n /** Watch mode config */\n watch?: {\n debounce?: number;\n exclude?: string[];\n };\n}\n\nconst defaults: XploitScanConfig = {\n exclude: [],\n ai: true,\n severity: \"low\",\n disableRules: [],\n};\n\nfunction loadXploitscanRc(directory: string): XploitScanRcConfig | null {\n try {\n const rcPath = join(directory, \".xploitscanrc\");\n const content = readFileSync(rcPath, \"utf-8\");\n return JSON.parse(content) as XploitScanRcConfig;\n } catch {\n return null;\n }\n}\n\nfunction mergeRcIntoConfig(\n base: XploitScanConfig,\n rc: XploitScanRcConfig,\n): XploitScanConfig {\n const merged = { ...base };\n\n // Merge rules\n if (rc.rules) {\n if (rc.rules.disable) {\n merged.disableRules = [\n ...new Set([...(merged.disableRules ?? []), ...rc.rules.disable]),\n ];\n }\n if (rc.rules.severityOverride) {\n merged.severityOverride = {\n ...(merged.severityOverride ?? {}),\n ...rc.rules.severityOverride,\n };\n }\n }\n\n // Merge scan settings\n if (rc.scan) {\n if (rc.scan.exclude) {\n merged.exclude = [\n ...new Set([...(merged.exclude ?? []), ...rc.scan.exclude]),\n ];\n }\n if (rc.scan.maxFileSize !== undefined) {\n merged.maxFileSize = rc.scan.maxFileSize;\n }\n if (rc.scan.extensions) {\n merged.extensions = [\n ...new Set([...(merged.extensions ?? []), ...rc.scan.extensions]),\n ];\n }\n }\n\n // Merge output settings (rc takes priority)\n if (rc.output) {\n if (rc.output.format !== undefined) {\n merged.format = rc.output.format;\n }\n if (rc.output.verbose !== undefined) {\n merged.verbose = rc.output.verbose;\n }\n }\n\n // Merge watch settings\n if (rc.watch) {\n merged.watch = {\n ...(merged.watch ?? {}),\n ...rc.watch,\n };\n }\n\n return merged;\n}\n\nexport async function loadConfig(\n directory: string,\n): Promise<XploitScanConfig> {\n const explorer = cosmiconfig(\"xploitscan\");\n\n let config = { ...defaults };\n\n try {\n const result = await explorer.search(directory);\n if (result && result.config) {\n config = { ...defaults, ...result.config };\n }\n } catch {\n // Config loading failed, use defaults\n }\n\n // Load .xploitscanrc and merge (rc takes priority)\n const rc = loadXploitscanRc(directory);\n if (rc) {\n config = mergeRcIntoConfig(config, rc);\n }\n\n return config;\n}\n","import type { CustomRule, Finding, RuleMatch } from \"../types.js\";\nimport { readFileContents, getSnippet } from \"../utils/files.js\";\n\n// ────────────────────────────────────────────\n// GLOBAL PRE-FILTERS\n// Reduces false positives before any rule runs\n// ────────────────────────────────────────────\n\n// Broad test/mock/fixture file detection\nconst TEST_FILE_PATTERN = /(?:\\.test\\.|\\.spec\\.|__tests__|__mocks__|\\.stories\\.|\\.story\\.|\\/test\\/|\\/tests\\/|\\/fixtures?\\/|\\/mocks?\\/|\\.mock\\.|test-utils|testing|\\.cy\\.|\\.e2e\\.)/i;\n\nfunction isTestFile(filePath: string): boolean {\n return TEST_FILE_PATTERN.test(filePath);\n}\n\n// Check if a match falls on a comment line (JS/TS/Python/Ruby/YAML/HTML)\nfunction isCommentLine(content: string, matchIndex: number): boolean {\n const lineStart = content.lastIndexOf(\"\\n\", matchIndex - 1) + 1;\n const lineText = content.substring(lineStart, content.indexOf(\"\\n\", matchIndex)).trimStart();\n return (\n lineText.startsWith(\"//\") ||\n lineText.startsWith(\"#\") ||\n lineText.startsWith(\"*\") ||\n lineText.startsWith(\"/*\") ||\n lineText.startsWith(\"<!--\") ||\n lineText.startsWith(\"'\") && lineText.length > 1 && /\\.(vb|bas)$/i.test(\"\") // VB comments\n );\n}\n\n// Check if a match is inside a string literal that's a fix/description message\n// (e.g., inside a findMatches callback or rule description)\nfunction isInsideFixMessage(content: string, matchIndex: number): boolean {\n const lineStart = content.lastIndexOf(\"\\n\", matchIndex - 1) + 1;\n const lineText = content.substring(lineStart, content.indexOf(\"\\n\", matchIndex));\n // Skip if the line looks like a fix suggestion string or rule description\n return /(?:fix|description|message|suggestion|hint|help|example|doc|comment)\\s*[:=(]/i.test(lineText) ||\n /return\\s*[\"'`].*(?:Use|Replace|Add|Move|Set|Enable|Disable|Never|Don't|Do not|Instead)/i.test(lineText);\n}\n\n// Context-aware matching: checks if mitigation exists within N lines after the match\nfunction hasMitigationNearby(content: string, matchIndex: number, mitigationPattern: RegExp, linesAhead: number = 5): boolean {\n const lines = content.split(\"\\n\");\n const matchLine = content.substring(0, matchIndex).split(\"\\n\").length - 1;\n const endLine = Math.min(matchLine + linesAhead, lines.length - 1);\n const nearbyContent = lines.slice(matchLine, endLine + 1).join(\"\\n\");\n return mitigationPattern.test(nearbyContent);\n}\n\n// Helper to find all regex matches with line numbers\n// Automatically skips matches on comment lines and fix messages\nfunction findMatches(\n content: string,\n pattern: RegExp,\n rule: Omit<CustomRule, \"check\">,\n filePath: string,\n fixTemplate?: (match: RegExpExecArray) => string,\n): RuleMatch[] {\n const matches: RuleMatch[] = [];\n const lines = content.split(\"\\n\");\n let m: RegExpExecArray | null;\n const re = new RegExp(pattern.source, pattern.flags.includes(\"g\") ? pattern.flags : `${pattern.flags}g`);\n\n while ((m = re.exec(content)) !== null) {\n // Skip matches on comment lines\n if (isCommentLine(content, m.index)) continue;\n // Skip matches inside fix/description strings\n if (isInsideFixMessage(content, m.index)) continue;\n\n const lineNum = content.substring(0, m.index).split(\"\\n\").length;\n matches.push({\n rule: rule.id,\n title: rule.title,\n severity: rule.severity,\n category: rule.category,\n file: filePath,\n line: lineNum,\n snippet: getSnippet(content, lineNum),\n fix: fixTemplate?.(m),\n });\n }\n\n return matches;\n}\n\n// ────────────────────────────────────────────\n// RULE DEFINITIONS\n// ────────────────────────────────────────────\n\nconst hardcodedSecrets: CustomRule = {\n id: \"VC001\",\n title: \"Hardcoded API Key or Secret\",\n severity: \"critical\",\n category: \"Secrets\",\n description: \"API keys, tokens, or secrets hardcoded in source code can be extracted by anyone with access to the code.\",\n check(content, filePath) {\n // Skip .env.example, template, test, and documentation files\n if (filePath.endsWith(\".example\") || filePath.endsWith(\".template\")) return [];\n if (isTestFile(filePath)) return [];\n if (filePath.match(/\\.(md|txt|rst|adoc)$/)) return [];\n\n const patterns = [\n // Generic API key patterns — require actual value assignment, not variable declarations\n /(?:api[_-]?key|apikey|api[_-]?secret)\\s*[:=]\\s*[\"'`]([a-zA-Z0-9_\\-]{20,})[\"'`]/gi,\n // AWS keys\n /(?:AKIA|ABIA|ACCA|ASIA)[A-Z0-9]{16}/g,\n // Stripe keys\n /(?:sk_live|pk_live|sk_test|pk_test)_[a-zA-Z0-9]{20,}/g,\n // Supabase anon/service keys (JWT format)\n /(?:supabase[_-]?(?:anon|service)[_-]?key|SUPABASE_(?:ANON|SERVICE_ROLE)_KEY)\\s*[:=]\\s*[\"'`](eyJ[a-zA-Z0-9_-]{50,})[\"'`]/gi,\n // OpenAI keys\n /sk-[a-zA-Z0-9]{20,}T3BlbkFJ[a-zA-Z0-9]{20,}/g,\n // Generic tokens in assignments — require standalone word and longer min length\n /(?:^|[\\s,({])(?:token|secret|password|passwd|pwd)\\s*[:=]\\s*[\"'`]([a-zA-Z0-9_\\-!@#$%^&*]{20,})[\"'`]/gim,\n // Private keys\n /-----BEGIN (?:RSA |EC |DSA )?PRIVATE KEY-----/g,\n // Database URLs with credentials\n /(?:postgres|mysql|mongodb(?:\\+srv)?):\\/\\/[^:]+:[^@]+@[^/\\s\"'`]+/gi,\n ];\n\n const matches: RuleMatch[] = [];\n for (const pattern of patterns) {\n const rawMatches = findMatches(content, pattern, hardcodedSecrets, filePath, () =>\n \"Move this secret to an environment variable and add it to .env (not committed to git). Use .env.example to document the required variables.\"\n );\n // Skip matches where the matched secret value is less than 12 characters\n for (const rm of rawMatches) {\n const lineText = content.split(\"\\n\")[rm.line - 1] || \"\";\n // Skip comment lines (additional guard beyond findMatches)\n const trimmed = lineText.trimStart();\n if (trimmed.startsWith(\"//\") || trimmed.startsWith(\"#\")) continue;\n // Extract the secret value from the match and skip short ones\n const secretMatch = lineText.match(/[:=]\\s*[\"'`]([^\"'`]*)[\"'`]/);\n if (secretMatch && secretMatch[1].length < 12) continue;\n matches.push(rm);\n }\n }\n return matches;\n },\n};\n\nconst exposedEnvFile: CustomRule = {\n id: \"VC002\",\n title: \"Environment File May Be Committed\",\n severity: \"high\",\n category: \"Secrets\",\n description: \".env files containing secrets may be committed to version control.\",\n check(content, filePath) {\n // Only applies to .env files (not .env.example)\n if (!filePath.match(/\\.env(?:\\.[a-z]+)?$/) || filePath.includes(\"example\")) return [];\n\n const hasSecrets = /(?:KEY|SECRET|TOKEN|PASSWORD|PRIVATE|DATABASE_URL)\\s*=/i.test(content);\n if (!hasSecrets) return [];\n\n return [{\n rule: \"VC002\",\n title: exposedEnvFile.title,\n severity: \"high\",\n category: \"Secrets\",\n file: filePath,\n line: 1,\n snippet: getSnippet(content, 1),\n fix: 'Add \".env*\" to your .gitignore file and remove this file from git history with: git rm --cached ' + filePath,\n }];\n },\n};\n\nconst missingAuthMiddleware: CustomRule = {\n id: \"VC003\",\n title: \"API Route Missing Authentication\",\n severity: \"high\",\n category: \"Authentication\",\n description: \"API routes without authentication checks allow unauthorized access.\",\n check(content, filePath) {\n // Only check API route files\n const isApiRoute = /(?:\\/api\\/|routes?\\/|controllers?\\/|endpoints?\\/)/.test(filePath) ||\n filePath.includes(\"server.\");\n if (!isApiRoute) return [];\n\n // Look for route handlers without auth checks\n const routePatterns = [\n // Express/Hono style\n /\\.(get|post|put|patch|delete)\\s*\\(\\s*[\"'`][^\"'`]+[\"'`]\\s*,\\s*(?:async\\s+)?\\(?(?:req|c|ctx)/gi,\n // Next.js API routes\n /export\\s+(?:async\\s+)?function\\s+(?:GET|POST|PUT|PATCH|DELETE)\\s*\\(/gi,\n ];\n\n // Skip test files\n if (filePath.includes(\"test\") || filePath.includes(\"spec\") || filePath.includes(\"mock\")) return [];\n\n const authPatterns = [\n /auth/i, /session/i, /jwt/i, /bearer/i, /middleware/i,\n /getUser/i, /currentUser/i, /isAuthenticated/i, /requireAuth/i,\n /clerk/i, /supabase\\.auth/i, /getServerSession/i, /getToken/i,\n /protect/i, /guard/i, /verifyToken/i, /validateToken/i, /withAuth/i,\n /passport/i, /firebase\\.auth/i, /cognito/i,\n ];\n\n const hasAuth = authPatterns.some((p) => p.test(content));\n if (hasAuth) return [];\n\n const matches: RuleMatch[] = [];\n for (const pattern of routePatterns) {\n matches.push(\n ...findMatches(content, pattern, missingAuthMiddleware, filePath, () =>\n \"Add authentication middleware to protect this route. Check the user's session/token before processing the request.\"\n ),\n );\n }\n return matches;\n },\n};\n\nconst supabaseNoRLS: CustomRule = {\n id: \"VC004\",\n title: \"Supabase Client Without Row Level Security\",\n severity: \"critical\",\n category: \"Authorization\",\n description: \"Using Supabase with the service role key or bypassing RLS exposes all database rows to any user.\",\n check(content, filePath) {\n const matches: RuleMatch[] = [];\n\n // Service role key used in client-side code\n if (\n /supabase_service_role|service_role_key/i.test(content) &&\n (/[\"']use client[\"']/.test(content) || filePath.match(/\\.(jsx|tsx|vue|svelte)$/))\n ) {\n matches.push(\n ...findMatches(\n content,\n /service_role/gi,\n supabaseNoRLS,\n filePath,\n () => \"Never expose the service_role key in client-side code. Use the anon key with RLS policies instead.\",\n ),\n );\n }\n\n // .rpc() or direct table access without .auth\n if (/createClient/i.test(content) && /\\.from\\(/.test(content)) {\n const hasRLSBypass = /\\.rpc\\(|auth\\.admin|service_role/i.test(content);\n if (hasRLSBypass) {\n matches.push(\n ...findMatches(\n content,\n /\\.rpc\\(|auth\\.admin/gi,\n { ...supabaseNoRLS, title: \"Supabase RLS Bypass Detected\" },\n filePath,\n () => \"Ensure RLS policies are enabled on all tables and avoid bypassing them with service_role or admin methods in user-facing code.\",\n ),\n );\n }\n }\n\n return matches;\n },\n};\n\nconst stripeWebhookUnprotected: CustomRule = {\n id: \"VC005\",\n title: \"Unprotected Stripe Webhook Endpoint\",\n severity: \"critical\",\n category: \"Payment Security\",\n description: \"Stripe webhook endpoints without signature verification allow attackers to fake payment events.\",\n check(content, filePath) {\n // Only check files that reference Stripe webhooks\n if (!/stripe|webhook/i.test(content)) return [];\n\n const hasWebhookRoute = /webhook/i.test(filePath) ||\n /(?:post|handler).*webhook/i.test(content);\n if (!hasWebhookRoute) return [];\n\n // Check for signature verification\n const hasVerification = /constructEvent|verifyHeader|stripe-signature|webhook_secret/i.test(content);\n if (hasVerification) return [];\n\n return findMatches(\n content,\n /webhook/gi,\n stripeWebhookUnprotected,\n filePath,\n () =>\n \"Verify the Stripe webhook signature using stripe.webhooks.constructEvent(body, sig, webhookSecret) to prevent forged payment events.\",\n );\n },\n};\n\nconst sqlInjection: CustomRule = {\n id: \"VC006\",\n title: \"Potential SQL Injection\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"String concatenation or template literals in SQL queries allow attackers to execute arbitrary database commands.\",\n check(content, filePath) {\n const patterns = [\n // Template literals in SQL\n /(?:query|execute|raw|sql)\\s*\\(\\s*`[^`]*\\$\\{/gi,\n // String concatenation in SQL\n /(?:query|execute)\\s*\\(\\s*[\"'][^\"']*[\"']\\s*\\+/gi,\n // Direct variable interpolation\n /(?:SELECT|INSERT|UPDATE|DELETE|WHERE)\\s+.*\\$\\{(?!.*parameterized)/gi,\n ];\n\n const matches: RuleMatch[] = [];\n\n // Skip if using parameterized queries / prepared statements\n const usesParams = /\\?\\s*,|\\$\\d+|:[\\w]+|\\bprepare\\b|\\bplaceholder\\b/i.test(content);\n if (usesParams) return [];\n\n for (const pattern of patterns) {\n matches.push(\n ...findMatches(content, pattern, sqlInjection, filePath, () =>\n \"Use parameterized queries or prepared statements instead of string interpolation. Example: db.query('SELECT * FROM users WHERE id = ?', [userId])\"\n ),\n );\n }\n return matches;\n },\n};\n\nconst xssVulnerability: CustomRule = {\n id: \"VC007\",\n title: \"Potential Cross-Site Scripting (XSS)\",\n severity: \"high\",\n category: \"Injection\",\n description: \"Rendering user input without sanitization allows attackers to inject malicious scripts.\",\n check(content, filePath) {\n // Skip if file is a sanitizer utility or already uses DOMPurify\n if (/(?:sanitize|purify|escape|xss)/i.test(filePath)) return [];\n if (/DOMPurify\\.sanitize|sanitizeHtml|xss\\(|escapeHtml/i.test(content)) return [];\n // Skip if the file imports or requires DOMPurify or a sanitize library anywhere\n if (/(?:import|require)\\s*\\(?.*(?:DOMPurify|dompurify|sanitize|sanitizer)/i.test(content)) return [];\n const patterns = [\n // React dangerouslySetInnerHTML\n /dangerouslySetInnerHTML\\s*=\\s*\\{\\s*\\{\\s*__html\\s*:/g,\n // Direct innerHTML assignment\n /\\.innerHTML\\s*=\\s*(?![\"'`]\\s*$)/gm,\n // document.write\n /document\\.write\\s*\\(/g,\n // v-html in Vue\n /v-html\\s*=/g,\n // {@html} in Svelte\n /\\{@html\\s/g,\n ];\n\n const matches: RuleMatch[] = [];\n for (const pattern of patterns) {\n matches.push(\n ...findMatches(content, pattern, xssVulnerability, filePath, () =>\n \"Sanitize user input before rendering as HTML. Use a library like DOMPurify: DOMPurify.sanitize(userInput)\"\n ),\n );\n }\n return matches;\n },\n};\n\nconst noRateLimiting: CustomRule = {\n id: \"VC008\",\n title: \"API Endpoint Without Rate Limiting\",\n severity: \"medium\",\n category: \"Availability\",\n description: \"API endpoints without rate limiting are vulnerable to abuse and denial-of-service attacks.\",\n check(content, filePath) {\n // Only check main server/app entry files\n const isEntryFile = /(?:server|app|index|main)\\.[jt]sx?$/.test(filePath) ||\n filePath.includes(\"middleware\");\n if (!isEntryFile) return [];\n\n // Check if this is a server file\n const isServer = /(?:express|hono|fastify|koa|next|createServer|listen\\()/i.test(content);\n if (!isServer) return [];\n\n // Check for rate limiting\n const hasRateLimit = /rate.?limit|throttle|express-rate-limit|@elysiajs\\/rate-limit|hono.*limiter/i.test(content);\n if (hasRateLimit) return [];\n\n return [{\n rule: \"VC008\",\n title: noRateLimiting.title,\n severity: \"medium\",\n category: \"Availability\",\n file: filePath,\n line: 1,\n snippet: getSnippet(content, 1),\n fix: \"Add rate limiting middleware to your server. For Express: npm install express-rate-limit. For other frameworks, check their rate limiting plugins.\",\n }];\n },\n};\n\nconst corsWildcard: CustomRule = {\n id: \"VC009\",\n title: \"CORS Allows All Origins\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Wildcard CORS (*) allows any website to make requests to your API, potentially exposing user data.\",\n check(content, filePath) {\n if (isTestFile(filePath)) return [];\n const patterns = [\n /cors\\(\\s*\\)/g, // cors() with no options = allow all\n /origin\\s*:\\s*[\"'`]\\*[\"'`]/g,\n /[\"'`]Access-Control-Allow-Origin[\"'`]\\s*,\\s*[\"'`]\\*[\"'`]/g,\n /origin\\s*:\\s*true/g,\n ];\n\n const matches: RuleMatch[] = [];\n for (const pattern of patterns) {\n matches.push(\n ...findMatches(content, pattern, corsWildcard, filePath, () =>\n \"Restrict CORS to your specific frontend domain(s): cors({ origin: 'https://yourdomain.com' })\"\n ),\n );\n }\n return matches;\n },\n};\n\nconst clientSideAuth: CustomRule = {\n id: \"VC010\",\n title: \"Client-Side Only Authorization\",\n severity: \"high\",\n category: \"Authorization\",\n description: \"Hiding UI elements based on roles without server-side checks lets attackers bypass restrictions using DevTools.\",\n check(content, filePath) {\n // Only check frontend component files\n if (!filePath.match(/\\.(jsx|tsx|vue|svelte)$/)) return [];\n\n const matches: RuleMatch[] = [];\n\n // Pattern: conditional rendering based on role/admin without server check\n const rolePatterns = [\n /\\{.*(?:isAdmin|role\\s*===?\\s*[\"'`]admin[\"'`]|user\\.role).*&&/gi,\n /v-if\\s*=\\s*[\"'`].*(?:isAdmin|role\\s*===?\\s*'admin')/gi,\n ];\n\n for (const pattern of rolePatterns) {\n // Only flag if the file has no server-side fetch for auth verification\n const hasServerCheck = /getServerSession|getUser|server|api\\/auth|middleware/i.test(content);\n if (hasServerCheck) continue;\n\n matches.push(\n ...findMatches(content, pattern, clientSideAuth, filePath, () =>\n \"Client-side role checks only hide UI — they don't prevent access. Always verify permissions on the server/API side too.\"\n ),\n );\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC011 – Secret in NEXT_PUBLIC_ env var\n// ────────────────────────────────────────────\n\nconst nextPublicSecret: CustomRule = {\n id: \"VC011\",\n title: \"Secret in NEXT_PUBLIC_ Environment Variable\",\n severity: \"critical\",\n category: \"Secrets\",\n description: \"NEXT_PUBLIC_ variables are exposed to the browser. Secrets placed here are visible to anyone.\",\n check(content, filePath) {\n if (!filePath.match(/\\.env/) && !filePath.match(/next\\.config/)) return [];\n const patterns = [\n /NEXT_PUBLIC_[A-Z_]*(?:SECRET|KEY|TOKEN|PASSWORD|PRIVATE)[A-Z_]*\\s*=\\s*.+/gi,\n /NEXT_PUBLIC_[A-Z_]*(?:SUPABASE_SERVICE|CLERK_SECRET|STRIPE_SECRET)[A-Z_]*\\s*=\\s*.+/gi,\n ];\n const matches: RuleMatch[] = [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, nextPublicSecret, filePath, () =>\n \"Remove the NEXT_PUBLIC_ prefix. Only use NEXT_PUBLIC_ for values safe to expose in the browser.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC012 – Firebase config in client code\n// ────────────────────────────────────────────\n\nconst firebaseClientConfig: CustomRule = {\n id: \"VC012\",\n title: \"Firebase Config with API Key in Client Code\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Firebase config objects in client code expose your API key. While Firebase API keys aren't secret, they should be restricted in the Firebase console.\",\n check(content, filePath) {\n if (!/firebase/i.test(content)) return [];\n const patterns = [\n /firebaseConfig\\s*=\\s*\\{[^}]*apiKey\\s*:/gi,\n /initializeApp\\s*\\(\\s*\\{[^}]*apiKey\\s*:/gi,\n ];\n const matches: RuleMatch[] = [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, firebaseClientConfig, filePath, () =>\n \"Move Firebase config to environment variables. Restrict the API key in Firebase Console > Project Settings > API restrictions.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC013 – Supabase anon key for admin ops\n// ────────────────────────────────────────────\n\nconst supabaseAnonAdmin: CustomRule = {\n id: \"VC013\",\n title: \"Supabase Anon Key Used for Admin Operations\",\n severity: \"high\",\n category: \"Authorization\",\n description: \"Using the Supabase anon key for operations that require elevated privileges is insecure.\",\n check(content, filePath) {\n if (!/supabase/i.test(content)) return [];\n if (!/anon/i.test(content)) return [];\n if (/service_role/i.test(content)) return [];\n const patterns = [\n /supabase[^.]*\\.auth\\.admin/gi,\n /supabase[^.]*\\.rpc\\s*\\(/gi,\n ];\n const matches: RuleMatch[] = [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, supabaseAnonAdmin, filePath, () =>\n \"Use the service_role key on the server side for admin operations. Never expose it to the client.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC014 – .env not in .gitignore\n// ────────────────────────────────────────────\n\nconst envNotGitignored: CustomRule = {\n id: \"VC014\",\n title: \".env File Not in .gitignore\",\n severity: \"high\",\n category: \"Secrets\",\n description: \"If .env is not listed in .gitignore, secrets will be committed to version control.\",\n check(content, filePath) {\n if (!filePath.endsWith(\".gitignore\")) return [];\n if (/\\.env/i.test(content)) return [];\n return [{\n rule: \"VC014\", title: envNotGitignored.title, severity: \"high\" as const, category: \"Secrets\",\n file: filePath, line: 1, snippet: getSnippet(content, 1),\n fix: 'Add \".env*\" to your .gitignore file to prevent committing secrets.',\n }];\n },\n};\n\n// ────────────────────────────────────────────\n// VC015 – eval() / new Function()\n// ────────────────────────────────────────────\n\nconst evalUsage: CustomRule = {\n id: \"VC015\",\n title: \"Use of eval() or Function Constructor\",\n severity: \"high\",\n category: \"Injection\",\n description: \"eval() and new Function() execute arbitrary code, creating severe injection risks. Common in AI-generated code.\",\n check(content, filePath) {\n if (filePath.includes(\"node_modules\") || filePath.includes(\".min.\")) return [];\n if (filePath.match(/(?:webpack|rollup|vite|jest|babel|tsup|esbuild)\\.config/i)) return [];\n if (isTestFile(filePath)) return [];\n // Skip files that are linters/scanners/rule engines (they reference eval in detection patterns)\n if (filePath.match(/(?:rules?|scanner|lint|check|detect|analyz)/i) && /\\.check\\s*\\(|findMatches/i.test(content)) return [];\n const patterns = [\n // Actual eval() calls — not in strings or regex patterns\n /\\beval\\s*\\(\\s*(?)/g,\n /new\\s+Function\\s*\\(\\s*(?![\"'`])/g,\n ];\n // Skip if eval is only in a string (e.g., devtool: 'eval-source-map')\n const hasEvalInString = /[\"'`]eval(?:-source-map|[\"'`])/i.test(content);\n if (hasEvalInString && !/\\beval\\s*\\([^)]*(?:req\\.|body\\.|input|params|user|data)/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n for (const p of patterns) {\n const rawMatches = findMatches(content, p, evalUsage, filePath, () =>\n \"Replace eval() with JSON.parse() for data, or a proper parser for expressions. Never pass user input to eval().\"\n );\n // Skip matches on lines containing devtool or source-map config\n for (const rm of rawMatches) {\n const lineStart = content.lastIndexOf(\"\\n\", content.split(\"\\n\").slice(0, rm.line - 1).join(\"\\n\").length) + 1;\n const lineEnd = content.indexOf(\"\\n\", lineStart + 1);\n const lineText = content.substring(lineStart, lineEnd === -1 ? content.length : lineEnd);\n if (/devtool|source-map/i.test(lineText)) continue;\n // Skip if eval appears on a line with description/title/message keys (string literal context)\n if (/(?:description|title|message)\\s*[:=]/i.test(lineText)) continue;\n matches.push(rm);\n }\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC016 – Unvalidated redirect\n// ────────────────────────────────────────────\n\nconst unvalidatedRedirect: CustomRule = {\n id: \"VC016\",\n title: \"Unvalidated Redirect\",\n severity: \"high\",\n category: \"Injection\",\n description: \"Redirecting users to URLs from untrusted input enables phishing attacks.\",\n check(content, filePath) {\n const patterns = [\n /window\\.location\\s*=\\s*(?![\"'`]https?:\\/\\/)/g,\n /window\\.location\\.href\\s*=\\s*(?![\"'`]https?:\\/\\/)/g,\n /window\\.location\\.assign\\s*\\(\\s*(?![\"'`]https?:\\/\\/)/g,\n /window\\.location\\.replace\\s*\\(\\s*(?![\"'`]https?:\\/\\/)/g,\n /res\\.redirect\\s*\\(\\s*(?:req\\.|params\\.|query\\.)/gi,\n ];\n const matches: RuleMatch[] = [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, unvalidatedRedirect, filePath, () =>\n \"Validate redirect URLs against an allowlist of trusted domains. Never redirect to user-supplied URLs directly.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC017 – Insecure cookie settings\n// ────────────────────────────────────────────\n\nconst insecureCookies: CustomRule = {\n id: \"VC017\",\n title: \"Insecure Cookie Settings\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Cookies without httpOnly, secure, or sameSite flags are vulnerable to theft and CSRF attacks.\",\n check(content, filePath) {\n if (isTestFile(filePath)) return [];\n if (!/cookie/i.test(content)) return [];\n const setCookiePattern = /(?:set-cookie|setCookie|cookie\\s*=|res\\.cookie\\s*\\()/gi;\n if (!setCookiePattern.test(content)) return [];\n const hasHttpOnly = /httpOnly\\s*:\\s*true|httponly/i.test(content);\n const hasSecure = /secure\\s*:\\s*true|;\\s*secure/i.test(content);\n const hasSameSite = /sameSite\\s*:|samesite/i.test(content);\n const matches: RuleMatch[] = [];\n if (!hasHttpOnly || !hasSecure || !hasSameSite) {\n const missing: string[] = [];\n if (!hasHttpOnly) missing.push(\"httpOnly\");\n if (!hasSecure) missing.push(\"secure\");\n if (!hasSameSite) missing.push(\"sameSite\");\n matches.push(...findMatches(content, /(?:set-cookie|setCookie|cookie\\s*=|res\\.cookie\\s*\\()/gi, insecureCookies, filePath, () =>\n `Add missing cookie flags: ${missing.join(\", \")}. Example: { httpOnly: true, secure: true, sameSite: 'lax' }`\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC018 – Exposed auth provider secret key\n// ────────────────────────────────────────────\n\nconst exposedAuthSecret: CustomRule = {\n id: \"VC018\",\n title: \"Exposed Clerk/Auth Secret Key\",\n severity: \"critical\",\n category: \"Secrets\",\n description: \"Auth provider secret keys (Clerk, Auth0, NextAuth) must never be in client-side code or NEXT_PUBLIC_ variables.\",\n check(content, filePath) {\n const isClientFile = filePath.match(/\\.(jsx|tsx|vue|svelte)$/) || /[\"']use client[\"']/.test(content);\n const isEnvFile = filePath.match(/\\.env/);\n if (!isClientFile && !isEnvFile) return [];\n const patterns: RegExp[] = [];\n if (isClientFile) {\n patterns.push(\n /CLERK_SECRET_KEY/g,\n /AUTH0_CLIENT_SECRET/g,\n /NEXTAUTH_SECRET/g,\n );\n }\n if (isEnvFile) {\n patterns.push(\n /NEXT_PUBLIC_CLERK_SECRET/gi,\n /NEXT_PUBLIC_AUTH0_SECRET/gi,\n /NEXT_PUBLIC_NEXTAUTH_SECRET/gi,\n );\n }\n const matches: RuleMatch[] = [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, exposedAuthSecret, filePath, () =>\n \"Move this secret to a server-side environment variable (without the NEXT_PUBLIC_ prefix). Never expose auth secrets to the browser.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC019 – Insecure Electron BrowserWindow\n// ────────────────────────────────────────────\n\nconst insecureElectronWindow: CustomRule = {\n id: \"VC019\",\n title: \"Insecure Electron BrowserWindow Configuration\",\n severity: \"high\",\n category: \"Configuration\",\n description: \"Electron BrowserWindow with nodeIntegration enabled, contextIsolation disabled, or sandbox disabled allows renderer processes to access Node.js APIs, enabling remote code execution.\",\n check(content, filePath) {\n if (isTestFile(filePath)) return [];\n if (!/BrowserWindow/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /nodeIntegration\\s*:\\s*true/g,\n /contextIsolation\\s*:\\s*false/g,\n /sandbox\\s*:\\s*false/g,\n /webSecurity\\s*:\\s*false/g,\n /allowRunningInsecureContent\\s*:\\s*true/g,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, insecureElectronWindow, filePath, (m) =>\n `Set ${m[0].split(\":\")[0].trim()}: ${m[0].includes(\"true\") ? \"false\" : \"true\"}. Enable contextIsolation, sandbox, and webSecurity; disable nodeIntegration and allowRunningInsecureContent.`\n ));\n }\n // Check for BrowserWindow without sandbox/webSecurity set at all\n if (/new\\s+BrowserWindow\\s*\\(/g.test(content)) {\n if (!/sandbox\\s*:/i.test(content)) {\n matches.push(...findMatches(content, /new\\s+BrowserWindow\\s*\\(/g, { ...insecureElectronWindow, title: \"Electron BrowserWindow Missing sandbox:true\" }, filePath, () =>\n \"Add sandbox: true to BrowserWindow webPreferences for defense in depth.\"\n ));\n }\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC020 – Missing Content Security Policy\n// ────────────────────────────────────────────\n\nconst missingCSP: CustomRule = {\n id: \"VC020\",\n title: \"Missing Content Security Policy (CSP)\",\n severity: \"high\",\n category: \"Configuration\",\n description: \"Without a Content-Security-Policy header or meta tag, your app is vulnerable to XSS and data injection attacks.\",\n check(content, filePath) {\n // Check HTML files for missing CSP meta tag\n if (filePath.match(/\\.(html|htm)$/)) {\n if (!/Content-Security-Policy/i.test(content)) {\n return [{\n rule: \"VC020\", title: missingCSP.title, severity: \"high\" as const, category: \"Configuration\",\n file: filePath, line: 1, snippet: getSnippet(content, 1),\n fix: 'Add a CSP meta tag: <meta http-equiv=\"Content-Security-Policy\" content=\"default-src \\'self\\'; script-src \\'self\\'\">'\n }];\n }\n }\n // Skip Electron main process — CSP is typically set in the HTML file (already checked above)\n // Flagging main.ts creates false positives since CSP belongs in index.html for Electron apps\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC021 – IPC Handler Without Path Validation\n// ────────────────────────────────────────────\n\nconst ipcPathTraversal: CustomRule = {\n id: \"VC021\",\n title: \"IPC/File Handler Without Path Validation\",\n severity: \"medium\",\n category: \"Injection\",\n description: \"IPC handlers that read or write files based on renderer-supplied paths without validation allow path traversal attacks, potentially exposing sensitive files like .ssh keys or .env files.\",\n check(content, filePath) {\n if (!/ipcMain\\.handle|ipcMain\\.on/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n // Look for file read/write in IPC handlers without path validation\n const hasFileOps = /readFile|writeFile|readFileSync|writeFileSync|createReadStream|createWriteStream/i.test(content);\n if (!hasFileOps) return [];\n const hasPathValidation = /(?:path\\.resolve|path\\.normalize|startsWith|isAbsolute|\\.includes\\s*\\(\\s*[\"'`]\\.\\.[\"'`]\\s*\\)|allowedPaths|safePath|validatePath|sanitizePath)/i.test(content);\n if (!hasPathValidation) {\n matches.push(...findMatches(content, /ipcMain\\.(?:handle|on)\\s*\\(\\s*[\"'`][^\"'`]*(?:read|write|file|save|load|open|export)[^\"'`]*[\"'`]/gi, ipcPathTraversal, filePath, () =>\n \"Validate file paths in IPC handlers: ensure paths are within an allowed directory (e.g., app.getPath('userData')), reject paths containing '..', and block access to sensitive directories (.ssh, .env, etc).\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC022 – HTML Export Without Sanitization\n// ────────────────────────────────────────────\n\nconst unsanitizedHTMLExport: CustomRule = {\n id: \"VC022\",\n title: \"HTML Export/Render Without Sanitization\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"Generating HTML from user content without sanitization (e.g., DOMPurify) allows stored XSS attacks. Malicious content saved in documents could execute scripts when exported or previewed.\",\n check(content, filePath) {\n if (isTestFile(filePath)) return [];\n // Skip if DOMPurify is imported or used anywhere in the file\n if (/DOMPurify|dompurify/i.test(content)) return [];\n // Skip React/Vue component files — JSX is not unsafe HTML concatenation\n if (filePath.match(/\\.(jsx|tsx|vue|svelte)$/) && !/innerHTML|document\\.write|\\.html\\s*=/i.test(content)) return [];\n // Skip files that have any sanitizer\n const hasSanitizer = /sanitize|escapeHtml|escapeHTML|xss|htmlEncode|purify/i.test(content);\n if (hasSanitizer) return [];\n // Only flag files that actually export/write HTML (not just template rendering)\n if (!/(?:export|download|save|write|send).*(?:html|HTML)|\\.innerHTML\\s*=|document\\.write|res\\.send\\s*\\(/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n const htmlBuildPatterns = [\n /`<[^`]*\\$\\{[^}]*(?:content|title|body|text|name|message|description|input|value|data)[^}]*\\}[^`]*>`/gi,\n /[\"']<[^\"']*['\"]\\s*\\+\\s*(?:content|title|body|text|message|data|doc\\.|post\\.|article\\.)/gi,\n ];\n for (const p of htmlBuildPatterns) {\n matches.push(...findMatches(content, p, unsanitizedHTMLExport, filePath, () =>\n \"Sanitize user content before embedding in HTML. Use DOMPurify: DOMPurify.sanitize(content). For plain text, use a function to escape HTML entities (<, >, &, quotes).\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC023 – Prototype Pollution via Storage\n// ────────────────────────────────────────────\n\nconst prototypePollution: CustomRule = {\n id: \"VC023\",\n title: \"Prototype Pollution Risk\",\n severity: \"high\",\n category: \"Injection\",\n description: \"Parsing JSON from localStorage, URL params, or external sources and merging it into objects without validation can lead to prototype pollution, allowing attackers to inject __proto__ or constructor properties.\",\n check(content, filePath) {\n const matches: RuleMatch[] = [];\n // JSON.parse from localStorage/sessionStorage without validation\n const storageParsePatterns = [\n /JSON\\.parse\\s*\\(\\s*(?:localStorage|sessionStorage)\\.getItem/g,\n /JSON\\.parse\\s*\\(\\s*window\\.localStorage/g,\n ];\n const hasValidation = /schema|validate|sanitize|whitelist|allowedKeys|pick\\(|Object\\.freeze|zod|yup|joi|ajv/i.test(content);\n if (hasValidation) return [];\n // Check for object spread/assign from parsed storage\n const hasUnsafeMerge = /Object\\.assign\\s*\\([^)]*JSON\\.parse|\\.\\.\\.JSON\\.parse|\\{.*\\.\\.\\.(?:stored|saved|cached|parsed|data)/i.test(content);\n if (hasUnsafeMerge) {\n matches.push(...findMatches(content, /Object\\.assign\\s*\\([^)]*JSON\\.parse|\\.\\.\\.JSON\\.parse/g, prototypePollution, filePath, () =>\n \"Validate parsed data against an expected schema before merging into objects. Use Object.freeze(), a validation library (Zod, Yup), or manually check for __proto__ and constructor keys.\"\n ));\n }\n for (const p of storageParsePatterns) {\n matches.push(...findMatches(content, p, prototypePollution, filePath, () =>\n \"Validate localStorage data against an expected schema before using it. Malicious extensions or XSS can modify localStorage values.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC024 – Missing File Size Limits\n// ────────────────────────────────────────────\n\nconst missingFileSizeLimits: CustomRule = {\n id: \"VC024\",\n title: \"File Write/Save Without Size Limit\",\n severity: \"medium\",\n category: \"Availability\",\n description: \"File save or upload handlers without size validation can lead to denial-of-service via disk exhaustion or memory exhaustion.\",\n check(content, filePath) {\n if (!/(?:writeFile|save|upload|export)/i.test(filePath) && !/(?:writeFile|writeFileSync|createWriteStream)/i.test(content)) return [];\n // Look for file write operations in handlers\n const hasWriteOps = /(?:ipcMain|app\\.(?:post|put)|router\\.(?:post|put)).*(?:writeFile|save|export)/is.test(content) ||\n /(?:writeFile|writeFileSync)\\s*\\(/g.test(content);\n if (!hasWriteOps) return [];\n const hasSizeCheck = /(?:size|length|byteLength|bytes)\\s*(?:>|>=|<|<=|===)\\s*\\d|maxSize|MAX_SIZE|sizeLimit|content-length/i.test(content);\n if (hasSizeCheck) return [];\n return findMatches(content, /(?:writeFile|writeFileSync)\\s*\\(/g, missingFileSizeLimits, filePath, () =>\n \"Add file size validation before writing. Check content.length or Buffer.byteLength() against a maximum (e.g., 10MB) to prevent disk exhaustion.\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC025 – Unsanitized Export Filenames\n// ────────────────────────────────────────────\n\nconst unsanitizedFilenames: CustomRule = {\n id: \"VC025\",\n title: \"Unsanitized Filename in File Operations\",\n severity: \"medium\",\n category: \"Injection\",\n description: \"Using user-supplied filenames without sanitization in file operations can enable path traversal, overwriting system files, or executing commands via special characters.\",\n check(content, filePath) {\n const matches: RuleMatch[] = [];\n // Look for file operations using variables as filenames\n const patterns = [\n /(?:writeFile|writeFileSync|createWriteStream|rename|copyFile)\\s*\\(\\s*(?:`[^`]*\\$\\{|[^\"'`\\s,]+\\s*\\+)/g,\n /(?:dialog\\.showSaveDialog|saveDialog).*(?:defaultPath|fileName)\\s*:\\s*(?![\"'`])/g,\n /\\.download\\s*=\\s*(?![\"'`])/g,\n ];\n const hasSanitization = /sanitize|cleanFilename|safeFilename|replace\\s*\\(\\s*\\/\\[.*\\]\\//i.test(content);\n if (hasSanitization) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, unsanitizedFilenames, filePath, () =>\n \"Sanitize filenames before use: strip path separators (/ \\\\), special chars, and '..' sequences. Example: name.replace(/[^a-zA-Z0-9._-]/g, '_')\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC026 – Electron Navigation Not Restricted\n// ────────────────────────────────────────────\n\nconst electronNavigationUnrestricted: CustomRule = {\n id: \"VC026\",\n title: \"Electron: External Navigation Not Blocked\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Electron apps that don't block navigation to external URLs or new window creation are vulnerable to phishing and drive-by downloads. Malicious links in app content can redirect the entire app to an attacker's site.\",\n check(content, filePath) {\n if (!/BrowserWindow|electron/i.test(content)) return [];\n if (!/main|index/i.test(filePath)) return [];\n const hasNavBlock = /will-navigate|new-window|setWindowOpenHandler|webContents\\.on.*navigate/i.test(content);\n if (hasNavBlock) return [];\n if (/new\\s+BrowserWindow/i.test(content)) {\n return findMatches(content, /new\\s+BrowserWindow\\s*\\(/g, electronNavigationUnrestricted, filePath, () =>\n \"Block external navigation: win.webContents.on('will-navigate', (e, url) => { if (!url.startsWith('file://')) e.preventDefault(); }); and use setWindowOpenHandler to block new windows.\"\n );\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC027 – Missing Security Meta Tags\n// ────────────────────────────────────────────\n\nconst missingSecurityMeta: CustomRule = {\n id: \"VC027\",\n title: \"Missing Security Meta Tags / Headers\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"HTML pages without X-Content-Type-Options, referrer policy, or other security meta tags are more susceptible to MIME-sniffing attacks and information leakage.\",\n check(content, filePath) {\n if (!filePath.match(/\\.(html|htm)$/)) return [];\n const matches: RuleMatch[] = [];\n if (!/X-Content-Type-Options/i.test(content) && !/<meta[^>]*nosniff/i.test(content)) {\n matches.push({\n rule: \"VC027\", title: \"Missing X-Content-Type-Options Header\", severity: \"medium\" as const,\n category: \"Configuration\", file: filePath, line: 1, snippet: getSnippet(content, 1),\n fix: 'Add <meta http-equiv=\"X-Content-Type-Options\" content=\"nosniff\"> to prevent MIME-type sniffing.'\n });\n }\n if (!/referrer/i.test(content)) {\n matches.push({\n rule: \"VC027\", title: \"Missing Referrer Policy\", severity: \"medium\" as const,\n category: \"Configuration\", file: filePath, line: 1, snippet: getSnippet(content, 1),\n fix: 'Add <meta name=\"referrer\" content=\"no-referrer\"> or \"strict-origin-when-cross-origin\" to limit referrer leakage.'\n });\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC028 – Unvalidated API Parameters\n// ────────────────────────────────────────────\n\nconst unvalidatedAPIParams: CustomRule = {\n id: \"VC028\",\n title: \"Unvalidated API Request Parameters\",\n severity: \"high\",\n category: \"Injection\",\n description: \"API requests constructed with unvalidated user input (API keys, model names, URLs) can be exploited for injection attacks or unauthorized access to different API models/endpoints.\",\n check(content, filePath) {\n const matches: RuleMatch[] = [];\n // API key passed without format validation\n const apiKeyPatterns = [\n /(?:apiKey|api_key|authorization)\\s*[:=]\\s*(?:req\\.body|req\\.query|params|input|formData|body)\\./gi,\n /headers\\s*:\\s*\\{[^}]*Authorization\\s*:\\s*(?![\"'`]Bearer\\s)/gi,\n ];\n const hasValidation = /validate|sanitize|regex|test\\(|match\\(|pattern|allowList|whitelist|enum|includes\\(/i.test(content);\n if (hasValidation) return [];\n // Model selection without allowlist\n if (/model\\s*[:=]\\s*(?:req\\.body|params|input|body)\\./i.test(content) || /model\\s*[:=]\\s*(?![\"'`])[a-z]/i.test(content)) {\n const hasModelValidation = /allowedModels|validModels|models\\s*\\.\\s*includes|model.*(?:===|!==|includes)/i.test(content);\n if (!hasModelValidation && /(?:openai|anthropic|claude|gpt|llm)/i.test(content)) {\n matches.push(...findMatches(content, /model\\s*[:=]\\s*(?:req\\.body|params|input|body)\\./gi, unvalidatedAPIParams, filePath, () =>\n \"Validate model selection against an allowlist of approved models. Example: const ALLOWED_MODELS = ['gpt-4', 'claude-3']; if (!ALLOWED_MODELS.includes(model)) throw new Error('Invalid model');\"\n ));\n }\n }\n for (const p of apiKeyPatterns) {\n matches.push(...findMatches(content, p, unvalidatedAPIParams, filePath, () =>\n \"Validate API key format before using it (e.g., check prefix and length). Never pass user-supplied API keys directly to third-party services without validation.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC029 – Unvalidated Event/Message Data\n// ────────────────────────────────────────────\n\nconst unvalidatedEventData: CustomRule = {\n id: \"VC029\",\n title: \"Unvalidated Event or PostMessage Data\",\n severity: \"medium\",\n category: \"Injection\",\n description: \"Custom events, postMessage, or IPC message data used without type-checking can lead to injection attacks or unexpected behavior when malicious data is sent through event channels.\",\n check(content, filePath) {\n const matches: RuleMatch[] = [];\n // addEventListener('message') without origin check\n if (/addEventListener\\s*\\(\\s*[\"'`]message[\"'`]/i.test(content)) {\n if (!/event\\.origin|e\\.origin|message\\.origin/i.test(content)) {\n matches.push(...findMatches(content, /addEventListener\\s*\\(\\s*[\"'`]message[\"'`]/g, unvalidatedEventData, filePath, () =>\n \"Always verify event.origin in message event handlers to prevent cross-origin attacks. Example: if (event.origin !== 'https://trusted.com') return;\"\n ));\n }\n }\n // dispatchEvent with custom data inserted without validation\n if (/new\\s+CustomEvent\\s*\\(/i.test(content) || /ipcRenderer\\.send/i.test(content)) {\n const hasTypeCheck = /typeof\\s|instanceof|z\\.|schema|validate|Number\\.isFinite|parseInt|parseFloat/i.test(content);\n if (!hasTypeCheck) {\n matches.push(...findMatches(content, /new\\s+CustomEvent\\s*\\(/g, unvalidatedEventData, filePath, () =>\n \"Type-check custom event data before using it. Validate that data.detail contains expected types to prevent injection.\"\n ));\n }\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC030 – Insecure Deserialization\n// ────────────────────────────────────────────\n\nconst insecureDeserialization: CustomRule = {\n id: \"VC030\",\n title: \"Insecure Deserialization\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"Deserializing untrusted data (pickle, unserialize, yaml.load) can execute arbitrary code. Attackers craft malicious payloads to gain remote code execution.\",\n check(content, filePath) {\n const matches: RuleMatch[] = [];\n const patterns = [\n // Python pickle\n /pickle\\.loads?\\s*\\(/g,\n /cPickle\\.loads?\\s*\\(/g,\n // PHP unserialize\n /unserialize\\s*\\(/g,\n // Ruby Marshal\n /Marshal\\.load\\s*\\(/g,\n // YAML unsafe load (Python)\n /yaml\\.load\\s*\\([^)]*(?!Loader\\s*=\\s*yaml\\.SafeLoader)/g,\n /yaml\\.unsafe_load\\s*\\(/g,\n // Java ObjectInputStream\n /ObjectInputStream\\s*\\(/g,\n // Node.js node-serialize\n /serialize\\.unserialize\\s*\\(/g,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, insecureDeserialization, filePath, () =>\n \"Never deserialize untrusted data. Use JSON instead of pickle/Marshal/unserialize. For YAML, use yaml.safe_load(). Validate and sanitize all input before deserialization.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC031 – Hardcoded JWT Secret\n// ────────────────────────────────────────────\n\nconst hardcodedJWTSecret: CustomRule = {\n id: \"VC031\",\n title: \"Hardcoded JWT Secret\",\n severity: \"critical\",\n category: \"Secrets\",\n description: \"JWT tokens signed with a hardcoded string secret can be forged by anyone who reads the source code.\",\n check(content, filePath) {\n if (filePath.endsWith(\".example\") || filePath.endsWith(\".template\") || filePath.includes(\"test\")) return [];\n const patterns = [\n /jwt\\.sign\\s*\\([^,]+,\\s*[\"'`][^\"'`]{3,}[\"'`]/g,\n /jwt\\.verify\\s*\\([^,]+,\\s*[\"'`][^\"'`]{3,}[\"'`]/g,\n /jsonwebtoken.*secret\\s*[:=]\\s*[\"'`][^\"'`]{3,}[\"'`]/gi,\n /JWT_SECRET\\s*[:=]\\s*[\"'`][^\"'`]{3,}[\"'`]/g,\n ];\n const matches: RuleMatch[] = [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, hardcodedJWTSecret, filePath, () =>\n \"Move JWT secret to an environment variable: jwt.sign(payload, process.env.JWT_SECRET). Use a strong, random secret (256+ bits).\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC032 – Missing HTTPS Enforcement\n// ────────────────────────────────────────────\n\nconst missingHTTPS: CustomRule = {\n id: \"VC032\",\n title: \"Missing HTTPS Enforcement\",\n severity: \"high\",\n category: \"Configuration\",\n description: \"HTTP URLs in production code, missing HSTS headers, or insecure redirect configurations expose data to man-in-the-middle attacks.\",\n check(content, filePath) {\n if (filePath.endsWith(\".example\") || filePath.includes(\"test\") || filePath.includes(\"README\")) return [];\n if (filePath.match(/\\.(md|txt)$/)) return [];\n const matches: RuleMatch[] = [];\n // Skip standard XML/HTML doctypes, DTDs, schema URIs, namespace URLs\n if (/<!DOCTYPE|xmlns|\\.dtd|\\.xsd/i.test(content) && !/fetch|axios|request|http\\.get/i.test(content)) return [];\n // Hardcoded http:// URLs to non-local hosts (excluding standard schema/namespace URIs)\n const httpPattern = /[\"'`]http:\\/\\/(?!localhost|127\\.0\\.0\\.1|0\\.0\\.0\\.0|192\\.168\\.|10\\.|172\\.(?:1[6-9]|2\\d|3[01])\\.|www\\.w3\\.org|www\\.apple\\.com\\/DTDs|schemas?\\.|xml\\.org|purl\\.org|ns\\.adobe|xmlpull\\.org|java\\.sun\\.com)[^\"'`\\s]+[\"'`]/g;\n const rawMatches = findMatches(content, httpPattern, missingHTTPS, filePath, () =>\n \"Use https:// instead of http:// for all production URLs. Add HSTS header: Strict-Transport-Security: max-age=31536000; includeSubDomains\"\n );\n // Skip DOCTYPE/DTD URLs\n for (const rm of rawMatches) {\n const lineStart = content.lastIndexOf(\"\\n\", content.split(\"\\n\").slice(0, rm.line - 1).join(\"\\n\").length) + 1;\n const lineEnd = content.indexOf(\"\\n\", lineStart + 1);\n const matchText = content.substring(lineStart, lineEnd === -1 ? content.length : lineEnd);\n if (/DTD|DOCTYPE|w3\\.org|apple\\.com\\/DTDs/i.test(matchText)) continue;\n matches.push(rm);\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC033 – Exposed Debug/Dev Mode\n// ────────────────────────────────────────────\n\nconst exposedDebugMode: CustomRule = {\n id: \"VC033\",\n title: \"Debug/Development Mode Exposed\",\n severity: \"high\",\n category: \"Configuration\",\n description: \"Debug mode, verbose logging, or development configuration left in production code exposes internal details and may enable debug endpoints.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.endsWith(\".example\") || filePath.includes(\"node_modules\")) return [];\n if (filePath.match(/\\.env\\.development$/)) return []; // Expected in dev env files\n const matches: RuleMatch[] = [];\n const patterns = [\n // Debug flags set to true\n /DEBUG\\s*[:=]\\s*(?:true|1|[\"'`]true[\"'`]|[\"'`]\\*[\"'`])/g,\n // Django DEBUG\n /DEBUG\\s*=\\s*True/g,\n // Flask/Express debug mode\n /app\\.debug\\s*=\\s*True/g,\n /app\\.run\\s*\\([^)]*debug\\s*=\\s*True/g,\n // Source maps in production\n /devtool\\s*:\\s*[\"'`](?:eval|cheap|source-map|inline-source-map)[\"'`]/g,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, exposedDebugMode, filePath, () =>\n \"Disable debug mode in production. Use environment variables: DEBUG = process.env.NODE_ENV !== 'production'. Remove source maps from production builds.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC034 – Insecure Randomness\n// ────────────────────────────────────────────\n\nconst insecureRandomness: CustomRule = {\n id: \"VC034\",\n title: \"Insecure Randomness for Security-Sensitive Values\",\n severity: \"high\",\n category: \"Cryptography\",\n description: \"Math.random() is not cryptographically secure. Using it for tokens, session IDs, passwords, or OTPs makes them predictable.\",\n check(content, filePath) {\n if (isTestFile(filePath)) return [];\n // Only flag if Math.random is actually used (not just mentioned)\n if (!/Math\\.random\\s*\\(\\s*\\)/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n // Math.random used in security-critical assignments (narrower: require direct assignment on same line)\n const securityContext = /(?:token|secret|session|password|otp|nonce|salt|csrf|auth)\\s*[:=]\\s*.*Math\\.random/gi;\n const rawMatches = findMatches(content, securityContext, insecureRandomness, filePath, () =>\n \"Use crypto.randomUUID() or crypto.getRandomValues() for security-sensitive values. Math.random() is predictable.\"\n );\n // Skip non-security uses of Math.random (e.g., UI-related randomness)\n const nonSecurityVarNames = /(?:id|key|color|index|delay|position|size|width|height|offset|opacity|rotation|animation|random(?!.*(?:token|secret|key|password)))\\s*[:=]\\s*.*Math\\.random/i;\n for (const rm of rawMatches) {\n const lineText = content.split(\"\\n\")[rm.line - 1] || \"\";\n if (nonSecurityVarNames.test(lineText)) continue;\n matches.push(rm);\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC035 – Open Redirect via URL Params\n// ────────────────────────────────────────────\n\nconst openRedirectParams: CustomRule = {\n id: \"VC035\",\n title: \"Open Redirect via URL Parameters\",\n severity: \"high\",\n category: \"Injection\",\n description: \"Redirect parameters like ?redirect_url=, ?return_to=, ?next= passed directly to redirects enable phishing attacks.\",\n check(content, filePath) {\n const matches: RuleMatch[] = [];\n const patterns = [\n // Reading redirect-like query params and using in redirect\n /(?:redirect_url|redirect_uri|return_to|return_url|next|callback_url|continue|goto|target|dest|destination|forward|redir)\\s*(?:=|:)\\s*(?:req\\.query|req\\.params|searchParams|query|params)\\./gi,\n /redirect\\s*\\(\\s*(?:req\\.query|req\\.params|searchParams\\.get)\\s*\\(\\s*[\"'`](?:redirect|return|next|callback|url|goto)/gi,\n ];\n const hasValidation = /allowedUrls|allowedDomains|allowedHosts|validUrl|safeDomain|whitelist|startsWith.*https|new URL.*hostname/i.test(content);\n if (hasValidation) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, openRedirectParams, filePath, () =>\n \"Validate redirect URLs against an allowlist of trusted domains. Use: const url = new URL(input); if (!ALLOWED_HOSTS.includes(url.hostname)) reject.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC036 – Missing Error Boundary (React)\n// ────────────────────────────────────────────\n\nconst missingErrorBoundary: CustomRule = {\n id: \"VC036\",\n title: \"React App Missing Error Boundary\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"React apps without error boundaries display raw stack traces and component tree info to users when crashes occur, leaking internal details.\",\n check(content, filePath) {\n // Only check App.tsx, App.jsx, app.tsx, app.jsx files\n const basename = filePath.split(\"/\").pop() || \"\";\n if (!/^[Aa]pp\\.[jt]sx$/i.test(basename)) return [];\n // Skip .ts files (non-JSX)\n if (filePath.match(/\\.ts$/)) return [];\n // Only trigger if file contains JSX (< followed by an uppercase letter)\n if (!/<[A-Z]/.test(content)) return [];\n // Skip Electron main process files\n if (/(?:BrowserWindow|electron|ipcMain|app\\.on\\s*\\(\\s*[\"']ready)/i.test(content)) return [];\n if (/\\/main\\//.test(filePath) && !/react-dom|createRoot/i.test(content)) return [];\n // Must have React imports and render calls\n if (!/(?:import.*react|from\\s+['\"]react|require.*react)/i.test(content)) return [];\n if (!/(?:createRoot|ReactDOM\\.render)/i.test(content)) return [];\n const hasErrorBoundary = /ErrorBoundary|componentDidCatch|getDerivedStateFromError|error-boundary/i.test(content);\n if (hasErrorBoundary) return [];\n if (/createRoot|ReactDOM\\.render/i.test(content)) {\n return [{\n rule: \"VC036\", title: missingErrorBoundary.title, severity: \"medium\" as const, category: \"Configuration\",\n file: filePath, line: 1, snippet: getSnippet(content, 1),\n fix: \"Wrap your app in an ErrorBoundary component to catch rendering errors gracefully. Use react-error-boundary or create a class component with componentDidCatch.\"\n }];\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC037 – Exposed Stack Traces in API\n// ────────────────────────────────────────────\n\nconst exposedStackTraces: CustomRule = {\n id: \"VC037\",\n title: \"Stack Traces Exposed in API Responses\",\n severity: \"medium\",\n category: \"Information Leakage\",\n description: \"Returning error.stack or detailed error messages in API responses reveals internal code paths, file structure, and dependencies to attackers.\",\n check(content, filePath) {\n const isApiFile = /(?:\\/api\\/|routes?\\/|controllers?\\/|server\\.|middleware)/i.test(filePath);\n if (!isApiFile) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n // Sending stack trace in response\n /(?:res\\.(?:json|send|status)|c\\.json|return.*json)\\s*\\([^)]*(?:err\\.stack|error\\.stack|e\\.stack)/gi,\n /(?:res\\.(?:json|send|status)|c\\.json)\\s*\\([^)]*(?:err\\.message|error\\.message|e\\.message)/gi,\n // Express-style error with stack\n /(?:message|error)\\s*:\\s*(?:err|error|e)\\.(?:stack|message)/gi,\n ];\n const hasEnvCheck = /process\\.env\\.NODE_ENV\\s*(?:===|!==)\\s*[\"'`]production[\"'`]|NODE_ENV/i.test(content);\n if (hasEnvCheck) return []; // They're conditionally showing errors\n for (const p of patterns) {\n matches.push(...findMatches(content, p, exposedStackTraces, filePath, () =>\n \"Never expose error.stack or error.message to clients in production. Return generic error messages: { error: 'Something went wrong' }. Log details server-side only.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC038 – Insecure File Upload Type\n// ────────────────────────────────────────────\n\nconst insecureFileUpload: CustomRule = {\n id: \"VC038\",\n title: \"Insecure File Upload Validation\",\n severity: \"high\",\n category: \"Injection\",\n description: \"File uploads validated only by extension (not MIME type or content) allow attackers to upload executable files disguised as images or documents.\",\n check(content, filePath) {\n if (!/upload|multer|formidable|busboy|multipart/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n // Check for extension-only validation\n const hasExtCheck = /\\.(?:endsWith|match|test)\\s*\\([^)]*(?:\\.jpg|\\.png|\\.pdf|\\.doc|ext)/i.test(content);\n const hasMimeCheck = /mimetype|content-type|file\\.type|mime|magic\\.detect|file-type/i.test(content);\n if (hasExtCheck && !hasMimeCheck) {\n matches.push(...findMatches(content, /upload|multer|formidable|busboy/gi, insecureFileUpload, filePath, () =>\n \"Validate file uploads by MIME type AND magic bytes, not just extension. Use the 'file-type' package to detect actual file type from content. Also enforce size limits.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC039 – Missing Dependency Lock File\n// ────────────────────────────────────────────\n\nconst missingLockFile: CustomRule = {\n id: \"VC039\",\n title: \"Missing Dependency Lock File\",\n severity: \"medium\",\n category: \"Supply Chain\",\n description: \"Without a lockfile (package-lock.json, pnpm-lock.yaml, yarn.lock), dependency versions are unpinned and vulnerable to supply chain attacks via version substitution.\",\n check(content, filePath) {\n // Only check .gitignore for lock files being ignored\n if (!filePath.endsWith(\".gitignore\")) return [];\n const ignoresLock = /package-lock\\.json|pnpm-lock\\.yaml|yarn\\.lock/i.test(content);\n if (ignoresLock) {\n return findMatches(content, /(?:package-lock\\.json|pnpm-lock\\.yaml|yarn\\.lock)/gi, missingLockFile, filePath, () =>\n \"Remove the lockfile from .gitignore. Lockfiles should be committed to prevent supply chain attacks. They ensure exact versions are installed across all environments.\"\n );\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC040 – Exposed .git Directory\n// ────────────────────────────────────────────\n\nconst exposedGitDir: CustomRule = {\n id: \"VC040\",\n title: \"Exposed .git Directory via Web Server\",\n severity: \"critical\",\n category: \"Information Leakage\",\n description: \"Web server configs that don't block access to .git directories expose your entire source code, commit history, secrets, and credentials.\",\n check(content, filePath) {\n // Check web server configs\n if (!filePath.match(/(?:nginx|apache|httpd|caddy|\\.htaccess|vercel\\.json|netlify\\.toml|server\\.[jt]s)/i)) return [];\n // For static file servers, check they block .git\n if (/(?:static|serve|express\\.static|serveStatic|public)/i.test(content)) {\n const blocksGit = /\\.git|dotfiles|hidden/i.test(content);\n if (!blocksGit) {\n return findMatches(content, /(?:static|serve|express\\.static|serveStatic)\\s*\\(/g, exposedGitDir, filePath, () =>\n \"Block access to .git and other dotfiles in your static file server config. For Express: app.use('/.git', (req, res) => res.status(403).end()). For Nginx: location ~ /\\\\.git { deny all; }\"\n );\n }\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC041 – Server-Side Request Forgery (SSRF)\n// ────────────────────────────────────────────\n\nconst ssrfVulnerability: CustomRule = {\n id: \"VC041\",\n title: \"Potential Server-Side Request Forgery (SSRF)\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"Fetching URLs from user input without validation allows attackers to access internal services, cloud metadata endpoints (169.254.169.254), and private networks.\",\n check(content, filePath) {\n if (isTestFile(filePath)) return [];\n // Only check server-side files\n const isServerFile = /(?:\\/api\\/|routes?\\/|controllers?\\/|server\\.|handler|middleware)/i.test(filePath);\n if (!isServerFile) return [];\n const matches: RuleMatch[] = [];\n // Only flag direct user input passed to fetch — narrower pattern\n const patterns = [\n /(?:fetch|axios\\.get|axios\\.post|axios|got|request|http\\.get|https\\.get)\\s*\\(\\s*(?:req\\.(?:body|query|params))\\./gi,\n ];\n const hasValidation = /allowedHosts|allowedDomains|allowedUrls|safeDomain|whitelist|urlValidator|new URL.*hostname.*includes|isAllowedUrl|validateUrl|isValidUrl/i.test(content);\n if (hasValidation) return [];\n for (const p of patterns) {\n const rawMatches = findMatches(content, p, ssrfVulnerability, filePath, () =>\n \"Validate URLs against an allowlist before fetching. Block internal IPs: 127.0.0.1, 10.x, 172.16-31.x, 192.168.x, 169.254.169.254 (cloud metadata). Use: const url = new URL(input); if (!ALLOWED_HOSTS.includes(url.hostname)) throw new Error('Blocked');\"\n );\n // Skip if the variable passed to fetch is defined as a constant string earlier in the file\n for (const rm of rawMatches) {\n const lineText = content.split(\"\\n\")[rm.line - 1] || \"\";\n const varMatch = lineText.match(/(?:fetch|axios\\.\\w+|got|request|https?\\.get)\\s*\\(\\s*(\\w+)/);\n if (varMatch) {\n const varName = varMatch[1];\n // Check if this variable is defined as a const string literal earlier in the file\n const constDef = new RegExp(`const\\\\s+${varName}\\\\s*=\\\\s*[\"'\\`]https?://`, \"i\");\n if (constDef.test(content)) continue;\n }\n matches.push(rm);\n }\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC042 – Mass Assignment\n// ────────────────────────────────────────────\n\nconst massAssignment: CustomRule = {\n id: \"VC042\",\n title: \"Mass Assignment Vulnerability\",\n severity: \"high\",\n category: \"Authorization\",\n description: \"Spreading or assigning request body directly into database models allows attackers to set fields they shouldn't (e.g., isAdmin, role, verified).\",\n check(content, filePath) {\n const isApiFile = /(?:\\/api\\/|routes?\\/|controllers?\\/|server\\.|handler)/i.test(filePath);\n if (!isApiFile) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n // Object.assign(model, req.body)\n /Object\\.assign\\s*\\(\\s*(?:user|account|profile|record|doc|model|entity)[^,]*,\\s*(?:req\\.body|body|input|data)\\s*\\)/gi,\n // Spread req.body into create/update\n /(?:create|update|insert|save|findOneAndUpdate|updateOne|upsert)\\s*\\(\\s*\\{[^}]*\\.\\.\\.(?:req\\.body|body|input|data)/gi,\n // Direct req.body into DB\n /(?:create|insert|save)\\s*\\(\\s*(?:req\\.body|body)\\s*\\)/gi,\n ];\n const hasSanitization = /pick\\(|omit\\(|allowedFields|sanitize|whitelist|permit|strong_params/i.test(content);\n if (hasSanitization) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, massAssignment, filePath, () =>\n \"Never pass req.body directly to database operations. Explicitly pick allowed fields: const { name, email } = req.body; await db.create({ name, email });\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC043 – Timing Attack on Comparison\n// ────────────────────────────────────────────\n\nconst timingAttack: CustomRule = {\n id: \"VC043\",\n title: \"Timing-Unsafe Secret Comparison\",\n severity: \"medium\",\n category: \"Cryptography\",\n description: \"Using === to compare secrets, tokens, or hashes leaks information via timing side-channels. Attackers can determine the correct value one character at a time.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n const matches: RuleMatch[] = [];\n // Direct comparison of secrets/tokens/hashes\n const patterns = [\n /(?:token|secret|hash|digest|signature|hmac|apiKey|api_key)\\s*(?:===|!==)\\s*(?:req\\.|body\\.|params\\.|query\\.|input)/gi,\n /(?:req\\.|body\\.|params\\.|query\\.|input)[\\w.]*(?:token|secret|hash|digest|signature|hmac)\\s*(?:===|!==)/gi,\n ];\n const hasTimingSafe = /timingSafeEqual|constantTimeEqual|safeCompare|secureCompare/i.test(content);\n if (hasTimingSafe) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, timingAttack, filePath, () =>\n \"Use crypto.timingSafeEqual() for comparing secrets: crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b)). This prevents timing-based side-channel attacks.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC044 – Log Injection\n// ────────────────────────────────────────────\n\nconst logInjection: CustomRule = {\n id: \"VC044\",\n title: \"Potential Log Injection\",\n severity: \"medium\",\n category: \"Injection\",\n description: \"Logging unsanitized user input allows attackers to forge log entries, inject malicious content, or exploit log aggregation systems via newlines and special characters.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n const isServerFile = /(?:\\/api\\/|routes?\\/|controllers?\\/|server\\.|middleware|handler)/i.test(filePath);\n if (!isServerFile) return [];\n const matches: RuleMatch[] = [];\n // console.log/warn/error with req.body/query/params directly\n const patterns = [\n /console\\.(?:log|warn|error|info)\\s*\\([^)]*(?:req\\.body|req\\.query|req\\.params|req\\.headers)\\s*\\)/gi,\n /(?:logger|log)\\.(?:info|warn|error|debug)\\s*\\([^)]*(?:req\\.body|req\\.query|req\\.params)\\s*\\)/gi,\n ];\n const hasSanitization = /sanitize|escape|JSON\\.stringify|replace.*\\\\n/i.test(content);\n if (hasSanitization) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, logInjection, filePath, () =>\n \"Sanitize user input before logging: strip newlines and control characters. Use JSON.stringify() or a structured logger (e.g., pino, winston) that escapes values automatically.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC045 – Weak Password Requirements\n// ────────────────────────────────────────────\n\nconst weakPasswordRequirements: CustomRule = {\n id: \"VC045\",\n title: \"Weak Password Requirements\",\n severity: \"high\",\n category: \"Authentication\",\n description: \"Registration or password-change endpoints without minimum length or complexity validation allow weak passwords that are easily brute-forced.\",\n check(content, filePath) {\n if (isTestFile(filePath)) return [];\n if (!/(?:password|passwd|pwd)/i.test(content)) return [];\n if (!/(?:register|signup|sign.up|createUser|create.user|changePassword|resetPassword|set.password)/i.test(content) &&\n !/(?:\\/api\\/|routes?\\/|controllers?\\/)/i.test(filePath)) return [];\n // Check for validation anywhere in the file — broader detection of mitigation\n const hasValidation = /(?:password|pwd).*(?:\\.length|minLength|minlength|min_length)\\s*(?:>=?|<|>)\\s*\\d|(?:password|pwd).*(?:match|test|regex|pattern)|zxcvbn|password-validator|passwordStrength|isStrongPassword|joi\\.|yup\\.|zod\\.|validate|schema/i.test(content);\n if (hasValidation) return [];\n const hasPasswordHandling = /(?:password|pwd)\\s*[:=]\\s*(?:req\\.body|body|input|params|args)\\./i.test(content);\n if (!hasPasswordHandling) return [];\n const rawMatches = findMatches(content, /(?:password|pwd)\\s*[:=]\\s*(?:req\\.body|body|input|params|args)\\./gi, weakPasswordRequirements, filePath, () =>\n \"Enforce minimum password requirements: at least 8 characters, mix of letters/numbers/symbols. Use a library like zxcvbn for strength estimation.\"\n );\n // Skip if validation logic exists within 10 lines of the password assignment\n const lines = content.split(\"\\n\");\n const validationPattern = /\\.length|minLength|minlength|min_length|match|test|regex|pattern|validate|schema|zxcvbn|isStrongPassword/i;\n return rawMatches.filter((rm) => {\n const start = Math.max(0, rm.line - 1 - 10);\n const end = Math.min(lines.length, rm.line - 1 + 10);\n const nearby = lines.slice(start, end).join(\"\\n\");\n return !validationPattern.test(nearby);\n });\n },\n};\n\n// ────────────────────────────────────────────\n// VC046 – Session Fixation\n// ────────────────────────────────────────────\n\nconst sessionFixation: CustomRule = {\n id: \"VC046\",\n title: \"Session Fixation Risk\",\n severity: \"high\",\n category: \"Authentication\",\n description: \"Not regenerating session IDs after login allows attackers to pre-set a session ID and hijack the authenticated session.\",\n check(content, filePath) {\n if (!/(?:login|signin|sign.in|authenticate)/i.test(content)) return [];\n if (!/session/i.test(content)) return [];\n const hasRegenerate = /regenerate|destroy.*create|req\\.session\\.id\\s*=|session\\.regenerateId|rotateSession/i.test(content);\n if (hasRegenerate) return [];\n const hasLogin = /(?:login|signin|authenticate)\\s*(?:=|:|\\()/i.test(content);\n if (!hasLogin) return [];\n return findMatches(content, /(?:login|signin|authenticate)\\s*(?:=|:|\\()/gi, sessionFixation, filePath, () =>\n \"Regenerate the session ID after successful login: req.session.regenerate() (Express) or equivalent. This prevents session fixation attacks.\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC047 – Missing Brute Force Protection\n// ────────────────────────────────────────────\n\nconst missingBruteForce: CustomRule = {\n id: \"VC047\",\n title: \"Login Without Brute Force Protection\",\n severity: \"high\",\n category: \"Authentication\",\n description: \"Login endpoints without rate limiting, account lockout, or progressive delays are vulnerable to credential stuffing and brute force attacks.\",\n check(content, filePath) {\n const isLoginFile = /(?:login|signin|sign.in|auth)/i.test(filePath) || /(?:login|signin|authenticate).*(?:post|handler|route)/i.test(content);\n if (!isLoginFile) return [];\n if (!/(?:password|credential)/i.test(content)) return [];\n const hasBruteForce = /rate.?limit|throttle|lockout|maxAttempts|max_attempts|failedAttempts|loginAttempts|brute|express-brute|express-rate-limit|slowDown/i.test(content);\n if (hasBruteForce) return [];\n return findMatches(content, /\\.(post|handler)\\s*\\([^)]*(?:login|signin|auth)/gi, missingBruteForce, filePath, () =>\n \"Add brute force protection to login endpoints: rate limiting (5 attempts/minute), progressive delays, or account lockout after N failures. Use express-rate-limit or similar.\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC048 – NoSQL Injection\n// ────────────────────────────────────────────\n\nconst nosqlInjection: CustomRule = {\n id: \"VC048\",\n title: \"Potential NoSQL Injection\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"Passing unsanitized user input directly into MongoDB/NoSQL queries allows attackers to bypass authentication, extract data, or modify queries using operators like $gt, $ne, $regex.\",\n check(content, filePath) {\n if (!/(?:mongo|mongoose|findOne|findById|find\\(|collection|aggregate)/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n // Direct req.body in MongoDB queries\n /\\.find(?:One)?\\s*\\(\\s*(?:req\\.body|body|input|params)\\s*\\)/gi,\n /\\.find(?:One)?\\s*\\(\\s*\\{[^}]*:\\s*(?:req\\.body|body|input|params)\\./gi,\n // $where with user input\n /\\$where\\s*:\\s*(?![\"'`])/g,\n // Direct variable in query without sanitization\n /\\.(?:findOne|findById|deleteOne|updateOne|findOneAndUpdate)\\s*\\(\\s*\\{[^}]*:\\s*(?:req\\.(?:body|query|params))\\./gi,\n ];\n const hasSanitization = /sanitize|escape|mongo-sanitize|express-mongo-sanitize|validator|typeof.*===.*string/i.test(content);\n if (hasSanitization) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, nosqlInjection, filePath, () =>\n \"Sanitize MongoDB query inputs: use express-mongo-sanitize, validate types (ensure strings aren't objects), and avoid $where. Example: if (typeof input !== 'string') throw new Error('Invalid input');\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC049 – Exposed DB Credentials in Config\n// ────────────────────────────────────────────\n\nconst exposedDBCredentials: CustomRule = {\n id: \"VC049\",\n title: \"Database Credentials in Config File\",\n severity: \"critical\",\n category: \"Secrets\",\n description: \"Database connection strings with embedded usernames and passwords in committed config files expose credentials to anyone with repo access.\",\n check(content, filePath) {\n if (filePath.endsWith(\".example\") || filePath.endsWith(\".template\")) return [];\n if (!filePath.match(/(?:config|setting|database|db|knexfile|sequelize|drizzle|prisma)/i) && !filePath.match(/\\.(json|yaml|yml|toml|js|ts)$/)) return [];\n if (filePath.match(/\\.env/)) return []; // Handled by VC002\n const patterns = [\n // Connection strings with credentials\n /(?:host|server|database|db).*(?:password|passwd|pwd)\\s*[:=]\\s*[\"'`][^\"'`]{3,}[\"'`]/gi,\n // Inline connection URLs with credentials\n /(?:connection|database|db).*(?:postgres|mysql|mongodb|redis):\\/\\/[^:]+:[^@]+@/gi,\n ];\n const matches: RuleMatch[] = [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, exposedDBCredentials, filePath, () =>\n \"Move database credentials to environment variables. Use: process.env.DATABASE_URL instead of hardcoding connection strings in config files.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC050 – Missing DB Connection Encryption\n// ────────────────────────────────────────────\n\nconst missingDBEncryption: CustomRule = {\n id: \"VC050\",\n title: \"Database Connection Without SSL/TLS\",\n severity: \"high\",\n category: \"Configuration\",\n description: \"Database connections without SSL/TLS encryption transmit credentials and data in plaintext, allowing eavesdropping on the network.\",\n check(content, filePath) {\n if (!/(?:createConnection|createPool|createClient|connect|new.*Client|knex|sequelize|drizzle)/i.test(content)) return [];\n if (!/(?:postgres|mysql|mariadb|pg|mongo)/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n // SSL explicitly disabled\n const sslDisabled = [\n /ssl\\s*:\\s*false/gi,\n /sslmode\\s*[:=]\\s*[\"'`]?disable[\"'`]?/gi,\n /rejectUnauthorized\\s*:\\s*false/gi,\n ];\n for (const p of sslDisabled) {\n matches.push(...findMatches(content, p, missingDBEncryption, filePath, () =>\n \"Enable SSL/TLS for database connections: { ssl: { rejectUnauthorized: true } }. In production, always verify server certificates.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC051 – GraphQL Introspection Enabled\n// ────────────────────────────────────────────\n\nconst graphqlIntrospection: CustomRule = {\n id: \"VC051\",\n title: \"GraphQL Introspection Enabled in Production\",\n severity: \"medium\",\n category: \"Information Leakage\",\n description: \"GraphQL introspection exposes your entire API schema, types, queries, and mutations to attackers, making it easy to find attack vectors.\",\n check(content, filePath) {\n if (!/graphql/i.test(content) && !/graphql/i.test(filePath)) return [];\n const matches: RuleMatch[] = [];\n // Introspection explicitly enabled or not disabled\n if (/introspection\\s*:\\s*true/i.test(content)) {\n matches.push(...findMatches(content, /introspection\\s*:\\s*true/gi, graphqlIntrospection, filePath, () =>\n \"Disable GraphQL introspection in production: introspection: process.env.NODE_ENV !== 'production'. This prevents schema exposure.\"\n ));\n }\n // GraphQL server setup without introspection config\n if (/(?:ApolloServer|GraphQLServer|createYoga|buildSchema|makeExecutableSchema)\\s*\\(/i.test(content)) {\n if (!/introspection/i.test(content)) {\n matches.push(...findMatches(content, /(?:ApolloServer|GraphQLServer|createYoga)\\s*\\(/gi, graphqlIntrospection, filePath, () =>\n \"Explicitly disable introspection in production: new ApolloServer({ introspection: process.env.NODE_ENV !== 'production' })\"\n ));\n }\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC052 – Missing Request Size Limit\n// ────────────────────────────────────────────\n\nconst missingRequestSizeLimit: CustomRule = {\n id: \"VC052\",\n title: \"Missing Request Body Size Limit\",\n severity: \"medium\",\n category: \"Availability\",\n description: \"Express/Hono/Fastify servers without request body size limits are vulnerable to denial-of-service via oversized payloads that exhaust memory.\",\n check(content, filePath) {\n if (!/(?:server|app|index|main)\\.[jt]sx?$/.test(filePath)) return [];\n if (!/(?:express|hono|fastify|koa)/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n // express.json() without limit\n if (/express\\.json\\s*\\(\\s*\\)/g.test(content)) {\n matches.push(...findMatches(content, /express\\.json\\s*\\(\\s*\\)/g, missingRequestSizeLimit, filePath, () =>\n \"Set a body size limit: express.json({ limit: '1mb' }). Without this, attackers can send huge payloads to crash your server.\"\n ));\n }\n // bodyParser without limit\n if (/bodyParser\\.json\\s*\\(\\s*\\)/g.test(content)) {\n matches.push(...findMatches(content, /bodyParser\\.json\\s*\\(\\s*\\)/g, missingRequestSizeLimit, filePath, () =>\n \"Set a body size limit: bodyParser.json({ limit: '1mb' }).\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC053 – Hardcoded IP/Host Allowlist\n// ────────────────────────────────────────────\n\nconst hardcodedIPAllowlist: CustomRule = {\n id: \"VC053\",\n title: \"Hardcoded IP or Host Allowlist\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Hardcoded IP addresses or hostnames in allowlists are brittle and hard to update. They should be in environment variables or configuration files.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\") || filePath.match(/\\.(md|txt)$/)) return [];\n const matches: RuleMatch[] = [];\n // Arrays of IPs used in access control\n const patterns = [\n /(?:allowedIPs|allowed_ips|whitelist|allowlist|trustedHosts)\\s*[:=]\\s*\\[\\s*[\"'`]\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}/gi,\n /(?:allowedIPs|allowed_ips|whitelist|allowlist|trustedHosts)\\s*[:=]\\s*\\[\\s*[\"'`][\\w.-]+\\.(?:com|net|org|io)/gi,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, hardcodedIPAllowlist, filePath, () =>\n \"Move IP/host allowlists to environment variables or a config file: const allowed = process.env.ALLOWED_IPS?.split(',') || [];\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC054 – Sensitive Data in localStorage\n// ────────────────────────────────────────────\n\nconst sensitiveLocalStorage: CustomRule = {\n id: \"VC054\",\n title: \"Sensitive Data in localStorage\",\n severity: \"high\",\n category: \"Secrets\",\n description: \"Storing tokens, passwords, or secrets in localStorage is insecure — it's accessible to any JavaScript on the page (XSS) and persists indefinitely. Use httpOnly cookies instead.\",\n check(content, filePath) {\n if (!filePath.match(/\\.(jsx?|tsx?|vue|svelte)$/)) return [];\n if (isTestFile(filePath)) return [];\n // Skip test-related files (mock, spec in the path)\n if (/mock|spec/i.test(filePath)) return [];\n // Skip if localStorage.removeItem is used (cleanup code, not storage)\n if (!/localStorage\\.setItem|localStorage\\[/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /localStorage\\.setItem\\s*\\(\\s*[\"'`](?:token|access_token|auth_token|jwt|session|refresh_token|api_key|password|secret)/gi,\n /localStorage\\s*\\[\\s*[\"'`](?:token|access_token|auth_token|jwt|session|refresh_token|api_key|password|secret)/gi,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, sensitiveLocalStorage, filePath, () =>\n \"Don't store tokens/secrets in localStorage — use httpOnly cookies instead. localStorage is accessible to any XSS attack. For session tokens, set them as httpOnly, secure, sameSite cookies.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC055 – Exposed Source Maps in Production\n// ────────────────────────────────────────────\n\nconst exposedSourceMaps: CustomRule = {\n id: \"VC055\",\n title: \"Source Maps Exposed in Production\",\n severity: \"medium\",\n category: \"Information Leakage\",\n description: \"Source map files (.map) in production expose your original source code, comments, and internal logic to anyone who downloads them.\",\n check(content, filePath) {\n // Check build configs for source maps in production\n if (!filePath.match(/(?:webpack|vite|rollup|next)\\.config|tsconfig/i)) return [];\n const matches: RuleMatch[] = [];\n // Source maps enabled without environment check\n if (/(?:sourceMap|source-map|sourcemap)\\s*[:=]\\s*true/i.test(content)) {\n const hasEnvCheck = /process\\.env\\.NODE_ENV|NODE_ENV|production/i.test(content);\n if (!hasEnvCheck) {\n matches.push(...findMatches(content, /(?:sourceMap|source-map|sourcemap)\\s*[:=]\\s*true/gi, exposedSourceMaps, filePath, () =>\n \"Disable source maps in production builds: sourceMap: process.env.NODE_ENV !== 'production'. Or use 'hidden-source-map' to generate maps without exposing them.\"\n ));\n }\n }\n // productionSourceMap in Vue\n if (/productionSourceMap\\s*:\\s*true/i.test(content)) {\n matches.push(...findMatches(content, /productionSourceMap\\s*:\\s*true/gi, exposedSourceMaps, filePath, () =>\n \"Set productionSourceMap: false to avoid exposing source code in production.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC056 – Clickjacking / Missing X-Frame-Options\n// ────────────────────────────────────────────\n\nconst clickjacking: CustomRule = {\n id: \"VC056\",\n title: \"Clickjacking — Missing X-Frame-Options\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Without X-Frame-Options or frame-ancestors CSP directive, your page can be embedded in an attacker's iframe for UI redress (clickjacking) attacks.\",\n check(content, filePath) {\n // Check HTML files\n if (filePath.match(/\\.(html|htm)$/)) {\n if (!/X-Frame-Options|frame-ancestors/i.test(content)) {\n return [{\n rule: \"VC056\", title: clickjacking.title, severity: \"medium\" as const, category: \"Configuration\",\n file: filePath, line: 1, snippet: getSnippet(content, 1),\n fix: 'Add <meta http-equiv=\"X-Frame-Options\" content=\"DENY\"> or set frame-ancestors in CSP to prevent clickjacking.'\n }];\n }\n }\n // Check server configs\n if (/(?:server|app|index|main)\\.[jt]sx?$/.test(filePath)) {\n if (/(?:express|hono|fastify|koa)/i.test(content)) {\n if (!/X-Frame-Options|frame-ancestors|helmet/i.test(content)) {\n return findMatches(content, /(?:express|hono|fastify|koa)\\s*\\(/gi, clickjacking, filePath, () =>\n \"Add X-Frame-Options header: res.setHeader('X-Frame-Options', 'DENY'). Or use helmet: app.use(helmet()) which sets this and other security headers.\"\n );\n }\n }\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC057 – Overly Permissive IAM/Cloud Roles\n// ────────────────────────────────────────────\n\nconst overlyPermissiveIAM: CustomRule = {\n id: \"VC057\",\n title: \"Overly Permissive IAM/Cloud Permissions\",\n severity: \"critical\",\n category: \"Authorization\",\n description: \"Wildcard (*) permissions in AWS IAM, GCP, or Terraform configs grant unrestricted access, violating the principle of least privilege.\",\n check(content, filePath) {\n if (!filePath.match(/\\.(tf|hcl|json|yaml|yml)$/) && !filePath.match(/(?:iam|policy|role|permission)/i)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n // AWS IAM wildcard\n /[\"'`]Action[\"'`]\\s*:\\s*[\"'`]\\*[\"'`]/g,\n /[\"'`]Resource[\"'`]\\s*:\\s*[\"'`]\\*[\"'`]/g,\n // Terraform aws_iam\n /actions\\s*=\\s*\\[\\s*[\"'`]\\*[\"'`]\\s*\\]/g,\n /resources\\s*=\\s*\\[\\s*[\"'`]\\*[\"'`]\\s*\\]/g,\n // GCP bindings\n /role\\s*[:=]\\s*[\"'`]roles\\/(?:owner|editor)[\"'`]/g,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, overlyPermissiveIAM, filePath, () =>\n \"Follow the principle of least privilege: replace wildcard (*) with specific actions and resources. Example: 'Action': 's3:GetObject' instead of '*'.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC058 – Docker Running as Root\n// ────────────────────────────────────────────\n\nconst dockerRunAsRoot: CustomRule = {\n id: \"VC058\",\n title: \"Docker Container Running as Root\",\n severity: \"high\",\n category: \"Configuration\",\n description: \"Containers running as root give attackers full system access if they escape the container. Always run as a non-root user.\",\n check(content, filePath) {\n if (!filePath.match(/Dockerfile$/i)) return [];\n const hasUser = /^\\s*USER\\s+/m.test(content);\n if (hasUser) return [];\n return [{\n rule: \"VC058\", title: dockerRunAsRoot.title, severity: \"high\" as const, category: \"Configuration\",\n file: filePath, line: 1, snippet: getSnippet(content, 1),\n fix: \"Add a USER directive: RUN addgroup -S app && adduser -S app -G app\\\\nUSER app. Place it after installing dependencies but before COPY/CMD.\"\n }];\n },\n};\n\n// ────────────────────────────────────────────\n// VC059 – Exposed Ports in Docker Compose\n// ────────────────────────────────────────────\n\nconst exposedDockerPorts: CustomRule = {\n id: \"VC059\",\n title: \"Docker Compose Binding to All Interfaces\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Binding ports to 0.0.0.0 (default) in Docker Compose exposes services to the entire network. Bind to 127.0.0.1 for local-only access.\",\n check(content, filePath) {\n if (!filePath.match(/docker-compose|compose\\.(yaml|yml)$/i)) return [];\n const matches: RuleMatch[] = [];\n // ports: \"3000:3000\" or \"8080:80\" without binding to 127.0.0.1\n const portPattern = /ports:\\s*\\n(?:\\s*-\\s*[\"'`]?\\d+:\\d+[\"'`]?\\s*\\n?)+/g;\n if (portPattern.test(content) && !/127\\.0\\.0\\.1:/i.test(content)) {\n matches.push(...findMatches(content, /^\\s*-\\s*[\"'`]?\\d+:\\d+[\"'`]?/gm, exposedDockerPorts, filePath, () =>\n \"Bind to localhost only: '127.0.0.1:3000:3000' instead of '3000:3000'. This prevents external network access to the service.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC060 – Weak Hashing Algorithm\n// ────────────────────────────────────────────\n\nconst weakHashing: CustomRule = {\n id: \"VC060\",\n title: \"Weak Hashing Algorithm for Passwords\",\n severity: \"critical\",\n category: \"Cryptography\",\n description: \"MD5 and SHA1/SHA256 are too fast for password hashing — they can be brute-forced at billions of attempts per second. Use bcrypt, scrypt, or argon2 instead.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n // Skip if file also uses strong hashing (indicates migration or comparison code)\n if (/bcrypt|scrypt|argon2/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n // MD5/SHA used with password context\n const patterns = [\n /(?:md5|sha1|sha256|sha512)\\s*\\([^)]*(?:password|passwd|pwd)/gi,\n /createHash\\s*\\(\\s*[\"'`](?:md5|sha1|sha256)[\"'`]\\).*(?:password|passwd|pwd)/gi,\n /(?:password|passwd|pwd).*createHash\\s*\\(\\s*[\"'`](?:md5|sha1|sha256)[\"'`]\\)/gi,\n /hashlib\\.(?:md5|sha1|sha256)\\s*\\([^)]*(?:password|passwd|pwd)/gi,\n /Digest::(?:MD5|SHA1|SHA256).*(?:password|passwd|pwd)/gi,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, weakHashing, filePath, () =>\n \"Use bcrypt, scrypt, or argon2 for password hashing — they're intentionally slow. Example: const hash = await bcrypt.hash(password, 12);\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC061 – Disabled TLS Certificate Verification\n// ────────────────────────────────────────────\n\nconst disabledTLSVerification: CustomRule = {\n id: \"VC061\",\n title: \"Disabled TLS Certificate Verification\",\n severity: \"critical\",\n category: \"Cryptography\",\n description: \"Disabling TLS certificate verification (NODE_TLS_REJECT_UNAUTHORIZED=0 or rejectUnauthorized:false) makes all HTTPS connections vulnerable to man-in-the-middle attacks.\",\n check(content, filePath) {\n const matches: RuleMatch[] = [];\n const patterns = [\n /NODE_TLS_REJECT_UNAUTHORIZED\\s*[:=]\\s*[\"'`]?0[\"'`]?/g,\n /rejectUnauthorized\\s*:\\s*false/g,\n /verify\\s*[:=]\\s*false.*(?:ssl|tls|cert|https)/gi,\n /PYTHONHTTPSVERIFY\\s*[:=]\\s*[\"'`]?0[\"'`]?/g,\n /ssl_verify\\s*[:=]\\s*false/gi,\n /InsecureSkipVerify\\s*:\\s*true/g,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, disabledTLSVerification, filePath, () =>\n \"Never disable TLS certificate verification in production. Fix the root cause: install the correct CA certificate, or use NODE_EXTRA_CA_CERTS for custom CAs.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC062 – Hardcoded Encryption Key/IV\n// ────────────────────────────────────────────\n\nconst hardcodedEncryptionKey: CustomRule = {\n id: \"VC062\",\n title: \"Hardcoded Encryption Key or IV\",\n severity: \"critical\",\n category: \"Cryptography\",\n description: \"Hardcoded encryption keys and initialization vectors (IVs) in source code can be extracted to decrypt all data. IVs must be random per encryption operation.\",\n check(content, filePath) {\n if (filePath.endsWith(\".example\") || filePath.endsWith(\".template\")) return [];\n if (isTestFile(filePath)) return [];\n // Skip HTML/XML/config files — meta tags and config values are not encryption keys\n if (filePath.match(/\\.(html|htm|xml|plist|svg|xhtml)$/)) return [];\n // Skip files without any crypto-related code\n if (!/(?:cipher|encrypt|decrypt|crypto|aes|createCipher)/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n // Encryption key as string literal\n /(?:encryption_key|encryptionKey|cipher_key|cipherKey|aes_key|AES_KEY|ENCRYPTION_KEY)\\s*[:=]\\s*[\"'`][^\"'`]{8,}[\"'`]/g,\n // createCipheriv with hardcoded key\n /createCipher(?:iv)?\\s*\\(\\s*[\"'`][^\"'`]+[\"'`]\\s*,\\s*[\"'`][^\"'`]+[\"'`]/g,\n // Buffer.from with hardcoded key near cipher context\n /(?:key|iv|nonce)\\s*[:=]\\s*Buffer\\.from\\s*\\(\\s*[\"'`][^\"'`]{8,}[\"'`]/gi,\n // Static IV (should be random) — only in crypto context\n /(?:^|[\\s,({])(?:iv|nonce|initialVector)\\s*[:=]\\s*[\"'`][0-9a-fA-F]{16,}[\"'`]/gi,\n ];\n for (const p of patterns) {\n const rawMatches = findMatches(content, p, hardcodedEncryptionKey, filePath, () =>\n \"Move encryption keys to environment variables. Generate IVs randomly per operation: crypto.randomBytes(16). Never reuse IVs.\"\n );\n // Skip matches on lines containing CSP meta tags or security headers\n for (const rm of rawMatches) {\n const lineStart = content.lastIndexOf(\"\\n\", content.split(\"\\n\").slice(0, rm.line - 1).join(\"\\n\").length) + 1;\n const lineEnd = content.indexOf(\"\\n\", lineStart + 1);\n const lineText = content.substring(lineStart, lineEnd === -1 ? content.length : lineEnd);\n if (/meta\\s+http-equiv|Content-Security-Policy|X-Frame-Options|X-Content-Type/i.test(lineText)) continue;\n matches.push(rm);\n }\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC063 – dangerouslySetInnerHTML\n// ────────────────────────────────────────────\n\nconst dangerousInnerHTML: CustomRule = {\n id: \"VC063\",\n title: \"Unsanitized dangerouslySetInnerHTML\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"Using dangerouslySetInnerHTML without sanitization (DOMPurify) enables XSS attacks. User-controlled content injected as raw HTML can execute arbitrary JavaScript.\",\n check(content, filePath) {\n if (!filePath.match(/\\.(jsx|tsx)$/)) return [];\n if (!/dangerouslySetInnerHTML/i.test(content)) return [];\n const hasSanitize = /DOMPurify|sanitize|purify|xss|sanitizeHtml|isomorphic-dompurify/i.test(content);\n if (hasSanitize) return [];\n return findMatches(content, /dangerouslySetInnerHTML\\s*=\\s*\\{\\s*\\{/g, dangerousInnerHTML, filePath, () =>\n \"Sanitize HTML before using dangerouslySetInnerHTML: dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(content) }}. Install: npm install dompurify\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC064 – Exposed Next.js Server Actions\n// ────────────────────────────────────────────\n\nconst exposedServerActions: CustomRule = {\n id: \"VC064\",\n title: \"Next.js Server Action Without Auth Check\",\n severity: \"high\",\n category: \"Authorization\",\n description: \"Next.js Server Actions ('use server') are publicly callable endpoints. Without authentication checks, anyone can invoke them directly.\",\n check(content, filePath) {\n if (!filePath.match(/\\.(jsx?|tsx?)$/)) return [];\n if (!/[\"']use server[\"']/i.test(content)) return [];\n const hasAuth = /getServerSession|auth\\(\\)|currentUser|getUser|requireAuth|session|clerk|getAuth/i.test(content);\n if (hasAuth) return [];\n // Check if there are exported async functions (server actions)\n if (/export\\s+async\\s+function/i.test(content)) {\n return findMatches(content, /export\\s+async\\s+function\\s+\\w+/g, exposedServerActions, filePath, () =>\n \"Add authentication to Server Actions: const session = await getServerSession(); if (!session) throw new Error('Unauthorized');\"\n );\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC065 – Unprotected Next.js API Routes\n// ────────────────────────────────────────────\n\nconst unprotectedAPIRoutes: CustomRule = {\n id: \"VC065\",\n title: \"Unprotected Next.js API Route\",\n severity: \"high\",\n category: \"Authorization\",\n description: \"Next.js API routes under /api/ without authentication middleware can be called by anyone, exposing data or mutations.\",\n check(content, filePath) {\n if (!filePath.match(/\\/api\\/.*\\.(jsx?|tsx?)$/) && !filePath.match(/\\/app\\/api\\/.*route\\.(jsx?|tsx?)$/)) return [];\n // Skip health/public endpoints\n if (/health|status|public|webhook/i.test(filePath)) return [];\n const hasAuth = /getServerSession|auth\\(\\)|currentUser|getUser|requireAuth|session|clerk|getAuth|verifyToken|authenticate|middleware/i.test(content);\n if (hasAuth) return [];\n const hasHandler = /export\\s+(?:async\\s+)?function\\s+(?:GET|POST|PUT|DELETE|PATCH)|export\\s+default/i.test(content);\n if (hasHandler) {\n return findMatches(content, /export\\s+(?:async\\s+)?function\\s+(?:GET|POST|PUT|DELETE|PATCH)/g, unprotectedAPIRoutes, filePath, () =>\n \"Add authentication to API routes: const session = await getServerSession(authOptions); if (!session) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\"\n );\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC066 – Client Component Using Secrets\n// ────────────────────────────────────────────\n\nconst clientComponentSecret: CustomRule = {\n id: \"VC066\",\n title: \"Secret Used in Client Component\",\n severity: \"critical\",\n category: \"Secrets\",\n description: \"Using server-side secrets (process.env without NEXT_PUBLIC_) in 'use client' components exposes them in the browser bundle.\",\n check(content, filePath) {\n if (!filePath.match(/\\.(jsx?|tsx?)$/)) return [];\n if (!/[\"']use client[\"']/i.test(content)) return [];\n // process.env without NEXT_PUBLIC_ prefix in a client component\n const pattern = /process\\.env\\.(?!NEXT_PUBLIC_)[A-Z_]{3,}/g;\n if (pattern.test(content)) {\n return findMatches(content, /process\\.env\\.(?!NEXT_PUBLIC_)[A-Z_]{3,}/g, clientComponentSecret, filePath, () =>\n \"Server-side env vars are not available in client components and may leak in builds. Move this logic to a Server Component or API route.\"\n );\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC067 – Insecure Deep Link Handling\n// ────────────────────────────────────────────\n\nconst insecureDeepLink: CustomRule = {\n id: \"VC067\",\n title: \"Insecure Deep Link Handling\",\n severity: \"high\",\n category: \"Injection\",\n description: \"Deep links that navigate or execute actions without validating the URL scheme, host, or parameters can be exploited for phishing or unauthorized actions.\",\n check(content, filePath) {\n if (!/(?:Linking|DeepLinking|deep.?link|handleURL|openURL|url.?scheme)/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n // React Native Linking without validation\n const patterns = [\n /Linking\\.addEventListener\\s*\\([^)]*(?:url|link)/gi,\n /Linking\\.getInitialURL\\s*\\(\\)/g,\n /handleOpenURL|handleDeepLink|onDeepLink/gi,\n ];\n const hasValidation = /allowedSchemes|allowedHosts|validateURL|isAllowedURL|whitelist|URL.*hostname.*includes/i.test(content);\n if (hasValidation) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, insecureDeepLink, filePath, () =>\n \"Validate deep link URLs: check the scheme and host against an allowlist before navigating or executing actions.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC068 – Sensitive Data in AsyncStorage\n// ────────────────────────────────────────────\n\nconst sensitiveAsyncStorage: CustomRule = {\n id: \"VC068\",\n title: \"Sensitive Data in AsyncStorage\",\n severity: \"high\",\n category: \"Secrets\",\n description: \"React Native AsyncStorage is unencrypted. Storing tokens, passwords, or secrets there makes them readable by other apps or anyone with device access.\",\n check(content, filePath) {\n if (!/AsyncStorage/i.test(content)) return [];\n const patterns = [\n /AsyncStorage\\.setItem\\s*\\(\\s*[\"'`](?:token|access_token|auth_token|jwt|session|refresh_token|api_key|password|secret|private_key)/gi,\n ];\n const matches: RuleMatch[] = [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, sensitiveAsyncStorage, filePath, () =>\n \"Use react-native-keychain or expo-secure-store instead of AsyncStorage for sensitive data. These use the OS keychain (encrypted).\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC069 – Missing Certificate Pinning\n// ────────────────────────────────────────────\n\nconst missingCertPinning: CustomRule = {\n id: \"VC069\",\n title: \"Missing Certificate Pinning in Mobile App\",\n severity: \"medium\",\n category: \"Cryptography\",\n description: \"Mobile apps without SSL certificate pinning are vulnerable to MITM attacks via compromised or rogue CAs. Pin your API server's certificate.\",\n check(content, filePath) {\n // Only for mobile project files\n if (!/(?:react.native|expo|android|ios|mobile)/i.test(filePath) && !/(?:React.*Native|expo)/i.test(content)) return [];\n if (!/(?:fetch|axios|http|api|request)/i.test(content)) return [];\n // Check for HTTP client setup without pinning\n if (/axios\\.create|new\\s+(?:HttpClient|ApiClient)/i.test(content)) {\n const hasPinning = /pinning|certificate|cert|ssl|TrustKit|react-native-ssl-pinning|cert-pinner/i.test(content);\n if (!hasPinning) {\n return findMatches(content, /axios\\.create|new\\s+(?:HttpClient|ApiClient)/gi, missingCertPinning, filePath, () =>\n \"Add SSL certificate pinning: use react-native-ssl-pinning or TrustKit. This prevents MITM attacks via rogue certificates.\"\n );\n }\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC070 – Android Debuggable Flag\n// ────────────────────────────────────────────\n\nconst androidDebuggable: CustomRule = {\n id: \"VC070\",\n title: \"Android App Debuggable in Production\",\n severity: \"high\",\n category: \"Configuration\",\n description: \"android:debuggable='true' in AndroidManifest.xml allows attackers to attach debuggers, inspect memory, and bypass security controls.\",\n check(content, filePath) {\n if (!filePath.match(/AndroidManifest\\.xml$/i)) return [];\n if (/android:debuggable\\s*=\\s*[\"']true[\"']/i.test(content)) {\n return findMatches(content, /android:debuggable\\s*=\\s*[\"']true[\"']/gi, androidDebuggable, filePath, () =>\n \"Remove android:debuggable='true' or set it to false. Debug builds should use build variants, not manifest flags.\"\n );\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC071 – Django DEBUG=True\n// ────────────────────────────────────────────\n\nconst djangoDebug: CustomRule = {\n id: \"VC071\",\n title: \"Django DEBUG Mode Enabled\",\n severity: \"critical\",\n category: \"Configuration\",\n description: \"Django with DEBUG=True exposes detailed error pages with source code, database queries, environment variables, and installed apps to anyone.\",\n check(content, filePath) {\n if (!filePath.match(/settings\\.py$/i) && !filePath.match(/config.*\\.py$/i)) return [];\n if (/^\\s*DEBUG\\s*=\\s*True\\s*$/m.test(content)) {\n const hasEnvCheck = /os\\.environ|env\\(|config\\(|getenv/i.test(content);\n if (!hasEnvCheck) {\n return findMatches(content, /^\\s*DEBUG\\s*=\\s*True/gm, djangoDebug, filePath, () =>\n \"Use environment variable: DEBUG = os.environ.get('DEBUG', 'False') == 'True'. Never hardcode DEBUG=True.\"\n );\n }\n }\n return [];\n },\n};\n\n// ────────────────────────────────────────────\n// VC072 – Flask Hardcoded Secret Key\n// ────────────────────────────────────────────\n\nconst flaskSecretKey: CustomRule = {\n id: \"VC072\",\n title: \"Flask Secret Key Hardcoded\",\n severity: \"critical\",\n category: \"Secrets\",\n description: \"Hardcoded Flask secret_key allows attackers to forge sessions, CSRF tokens, and signed cookies. Must be a random value from environment variables.\",\n check(content, filePath) {\n if (!filePath.match(/\\.py$/)) return [];\n const patterns = [\n /(?:app\\.)?secret_key\\s*=\\s*[\"'`][^\"'`]{3,}[\"'`]/g,\n /(?:app\\.config)\\s*\\[\\s*[\"']SECRET_KEY[\"']\\s*\\]\\s*=\\s*[\"'`][^\"'`]{3,}[\"'`]/g,\n ];\n const hasEnv = /os\\.environ|env\\(|config\\(|getenv/i.test(content);\n if (hasEnv) return [];\n const matches: RuleMatch[] = [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, flaskSecretKey, filePath, () =>\n \"Use environment variable: app.secret_key = os.environ['SECRET_KEY']. Generate with: python -c \\\"import secrets; print(secrets.token_hex(32))\\\"\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC073 – Pickle Deserialization\n// ────────────────────────────────────────────\n\nconst pickleDeserialization: CustomRule = {\n id: \"VC073\",\n title: \"Unsafe Pickle Deserialization\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"pickle.loads() on untrusted data allows arbitrary code execution. An attacker can craft a pickle payload that runs system commands on your server.\",\n check(content, filePath) {\n if (!filePath.match(/\\.py$/)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /pickle\\.loads?\\s*\\(/g,\n /cPickle\\.loads?\\s*\\(/g,\n /shelve\\.open\\s*\\(/g,\n /yaml\\.load\\s*\\([^)]*(?!Loader\\s*=\\s*yaml\\.SafeLoader)/g,\n ];\n const hasSafe = /restricted_loads|SafeUnpickler|safe_load|yaml\\.safe_load/i.test(content);\n if (hasSafe) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, pickleDeserialization, filePath, () =>\n \"Never unpickle untrusted data — it allows arbitrary code execution. Use JSON for data exchange, or yaml.safe_load() for YAML.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC074 – Missing CSRF Protection (Django)\n// ────────────────────────────────────────────\n\nconst missingCSRF: CustomRule = {\n id: \"VC074\",\n title: \"CSRF Protection Disabled\",\n severity: \"high\",\n category: \"Authorization\",\n description: \"Using @csrf_exempt on state-changing views (POST/PUT/DELETE) allows attackers to forge requests from other sites, performing actions as authenticated users.\",\n check(content, filePath) {\n if (!filePath.match(/\\.py$/)) return [];\n const matches: RuleMatch[] = [];\n if (/csrf_exempt/i.test(content)) {\n matches.push(...findMatches(content, /@csrf_exempt/g, missingCSRF, filePath, () =>\n \"Remove @csrf_exempt and use proper CSRF tokens. For APIs, use token-based auth (JWT) instead of session cookies.\"\n ));\n }\n // Also check for CsrfViewMiddleware removal\n if (/MIDDLEWARE.*=.*\\[/s.test(content) && !/CsrfViewMiddleware/i.test(content) && /django/i.test(content)) {\n matches.push(...findMatches(content, /MIDDLEWARE\\s*=/g, missingCSRF, filePath, () =>\n \"Re-add 'django.middleware.csrf.CsrfViewMiddleware' to MIDDLEWARE. CSRF protection is essential for session-based auth.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC075 – GitHub Actions Script Injection\n// ────────────────────────────────────────────\n\nconst githubActionsInjection: CustomRule = {\n id: \"VC075\",\n title: \"GitHub Actions Script Injection\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"Using ${{ github.event.* }} directly in 'run:' steps allows attackers to inject shell commands via PR titles, issue bodies, or branch names.\",\n check(content, filePath) {\n if (!filePath.match(/\\.github\\/workflows\\/.*\\.(yml|yaml)$/i)) return [];\n const matches: RuleMatch[] = [];\n // Direct interpolation in run steps\n const patterns = [\n /run:.*\\$\\{\\{\\s*github\\.event\\.(?:issue|pull_request|comment|review|head_commit)\\.(?:title|body|message)/gi,\n /run:.*\\$\\{\\{\\s*github\\.event\\.(?:inputs|head_ref|base_ref)/gi,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, githubActionsInjection, filePath, () =>\n \"Never use ${{ github.event.* }} directly in 'run:'. Pass it as an environment variable: env: TITLE: ${{ github.event.issue.title }} then use $TITLE in the script.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC076 – Secrets in CI Config\n// ────────────────────────────────────────────\n\nconst secretsInCI: CustomRule = {\n id: \"VC076\",\n title: \"Hardcoded Secrets in CI/CD Config\",\n severity: \"critical\",\n category: \"Secrets\",\n description: \"Hardcoded tokens, passwords, or API keys in CI/CD workflow files are visible to anyone with repo access. Use encrypted secrets instead.\",\n check(content, filePath) {\n if (!filePath.match(/\\.github\\/workflows\\/|\\.gitlab-ci|Jenkinsfile|\\.circleci|bitbucket-pipelines/i)) return [];\n const matches: RuleMatch[] = [];\n // Hardcoded values that look like secrets (not using ${{ secrets.* }})\n const patterns = [\n /(?:password|token|key|secret|api_key|apikey)\\s*[:=]\\s*[\"'`][A-Za-z0-9+/=_-]{20,}[\"'`]/gi,\n /(?:DOCKER_PASSWORD|NPM_TOKEN|AWS_SECRET_ACCESS_KEY|GH_TOKEN|GITHUB_TOKEN)\\s*[:=]\\s*[\"'`][^\"'`$]+[\"'`]/gi,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, secretsInCI, filePath, () =>\n \"Use repository secrets: ${{ secrets.MY_TOKEN }} (GitHub) or CI/CD variable settings. Never hardcode credentials in workflow files.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC077 – CORS Wildcard in Serverless Config\n// ────────────────────────────────────────────\n\nconst corsServerless: CustomRule = {\n id: \"VC077\",\n title: \"CORS Wildcard in Serverless Config\",\n severity: \"high\",\n category: \"Configuration\",\n description: \"Setting Access-Control-Allow-Origin: * in serverless.yml, vercel.json, or similar configs allows any website to make authenticated requests to your API.\",\n check(content, filePath) {\n if (!filePath.match(/serverless\\.(yml|yaml)|vercel\\.json|netlify\\.toml|amplify\\.yml/i)) return [];\n const matches: RuleMatch[] = [];\n if (/(?:Access-Control-Allow-Origin|allowOrigin|cors).*['\"]\\*['\"]/i.test(content)) {\n matches.push(...findMatches(content, /(?:Access-Control-Allow-Origin|allowOrigin|cors).*['\"]\\*['\"]/gi, corsServerless, filePath, () =>\n \"Replace wildcard CORS with specific origins: allowOrigin: ['https://yourdomain.com']. Wildcard allows any site to call your API.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC078 – Kubernetes Privileged Container\n// ────────────────────────────────────────────\n\nconst k8sPrivileged: CustomRule = {\n id: \"VC078\",\n title: \"Kubernetes Privileged Container\",\n severity: \"critical\",\n category: \"Configuration\",\n description: \"Running containers with privileged: true or as root in Kubernetes gives full host access, making container escapes trivial.\",\n check(content, filePath) {\n if (!filePath.match(/\\.(yaml|yml)$/) || !/(?:kind|apiVersion|container)/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /privileged\\s*:\\s*true/g,\n /runAsUser\\s*:\\s*0\\b/g,\n /runAsNonRoot\\s*:\\s*false/g,\n /allowPrivilegeEscalation\\s*:\\s*true/g,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, k8sPrivileged, filePath, () =>\n \"Set securityContext: { privileged: false, runAsNonRoot: true, allowPrivilegeEscalation: false }. Never run containers as root in production.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// FRAMEWORK DETECTION\n// ────────────────────────────────────────────\n\nexport type DetectedFramework = \"next.js\" | \"react\" | \"react-native\" | \"express\" | \"hono\" | \"fastify\" | \"django\" | \"flask\" | \"electron\" | \"vue\" | \"svelte\" | \"unknown\";\n\nexport function detectFramework(files: { path: string; content: string }[]): DetectedFramework[] {\n const frameworks: Set<DetectedFramework> = new Set();\n for (const { path, content } of files) {\n if (path.match(/next\\.config/i) || /from\\s+[\"']next/i.test(content)) frameworks.add(\"next.js\");\n if (/from\\s+[\"']react-native/i.test(content) || path.match(/react-native\\.config/i)) frameworks.add(\"react-native\");\n else if (/from\\s+[\"']react/i.test(content) || /import\\s+React/i.test(content)) frameworks.add(\"react\");\n if (/from\\s+[\"']express/i.test(content) || /require\\s*\\(\\s*[\"']express/i.test(content)) frameworks.add(\"express\");\n if (/from\\s+[\"']hono/i.test(content)) frameworks.add(\"hono\");\n if (/from\\s+[\"']fastify/i.test(content)) frameworks.add(\"fastify\");\n if (/from\\s+[\"']electron/i.test(content) || path.match(/electron/i)) frameworks.add(\"electron\");\n if (path.match(/settings\\.py$/) || /from\\s+django/i.test(content)) frameworks.add(\"django\");\n if (/from\\s+flask/i.test(content) || /Flask\\s*\\(/i.test(content)) frameworks.add(\"flask\");\n if (/from\\s+[\"']vue/i.test(content) || path.match(/vue\\.config/i)) frameworks.add(\"vue\");\n if (/from\\s+[\"']svelte/i.test(content) || path.match(/svelte\\.config/i)) frameworks.add(\"svelte\");\n }\n if (frameworks.size === 0) frameworks.add(\"unknown\");\n return [...frameworks];\n}\n\n// ────────────────────────────────────────────\n// SEVERITY GRADING\n// ────────────────────────────────────────────\n\nexport type SecurityGrade = \"A+\" | \"A\" | \"B\" | \"C\" | \"D\" | \"F\";\n\nexport interface GradeResult {\n grade: SecurityGrade;\n score: number;\n summary: string;\n}\n\nexport function calculateGrade(findings: Finding[], totalFiles: number): GradeResult {\n if (findings.length === 0) {\n return { grade: \"A+\", score: 100, summary: \"No security issues detected. Excellent!\" };\n }\n\n // Weight by severity\n let deductions = 0;\n for (const f of findings) {\n switch (f.severity) {\n case \"critical\": deductions += 15; break;\n case \"high\": deductions += 8; break;\n case \"medium\": deductions += 4; break;\n case \"low\": deductions += 1; break;\n }\n }\n\n // Scale relative to project size (larger projects get a slight buffer)\n const sizeBuffer = Math.min(Math.log2(Math.max(totalFiles, 1)) * 2, 15);\n const score = Math.max(0, Math.min(100, 100 - deductions + sizeBuffer));\n\n let grade: SecurityGrade;\n let summary: string;\n\n if (score >= 95) { grade = \"A+\"; summary = \"Excellent security posture with minimal issues.\"; }\n else if (score >= 85) { grade = \"A\"; summary = \"Strong security with a few minor concerns.\"; }\n else if (score >= 70) { grade = \"B\"; summary = \"Good security but some issues need attention.\"; }\n else if (score >= 55) { grade = \"C\"; summary = \"Fair security — several vulnerabilities should be fixed.\"; }\n else if (score >= 35) { grade = \"D\"; summary = \"Poor security — critical issues require immediate attention.\"; }\n else { grade = \"F\"; summary = \"Failing — serious vulnerabilities present. Fix critical issues immediately.\"; }\n\n return { grade, score: Math.round(score), summary };\n}\n\n// ────────────────────────────────────────────\n// VC079 – JWT Algorithm Confusion\n// ────────────────────────────────────────────\n\nconst jwtAlgConfusion: CustomRule = {\n id: \"VC079\",\n title: \"JWT Algorithm Confusion (alg:none)\",\n severity: \"critical\",\n category: \"Authentication\",\n description: \"Accepting 'none' as a JWT algorithm allows attackers to forge tokens by removing the signature entirely.\",\n check(content, filePath) {\n if (!/jwt|jsonwebtoken|jose/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /algorithms\\s*:\\s*\\[.*[\"']none[\"']/gi,\n /algorithm\\s*[:=]\\s*[\"']none[\"']/gi,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, jwtAlgConfusion, filePath, () =>\n \"Never allow algorithm 'none'. Explicitly specify: algorithms: ['RS256'] or algorithms: ['HS256']. Reject tokens with alg:none.\"\n ));\n }\n // Also check for missing algorithm restriction\n if (/jwt\\.verify\\s*\\([^)]*\\)\\s*(?!.*algorithms)/i.test(content) && !/algorithms/i.test(content)) {\n matches.push(...findMatches(content, /jwt\\.verify\\s*\\(/g, jwtAlgConfusion, filePath, () =>\n \"Specify allowed algorithms in jwt.verify: jwt.verify(token, secret, { algorithms: ['HS256'] }).\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC080 – Regex DoS (ReDoS)\n// ────────────────────────────────────────────\n\nconst regexDos: CustomRule = {\n id: \"VC080\",\n title: \"Potential Regular Expression DoS (ReDoS)\",\n severity: \"high\",\n category: \"Availability\",\n description: \"Nested quantifiers like (a+)+ or (a*){2,} cause catastrophic backtracking, allowing attackers to freeze your server with crafted input.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n const matches: RuleMatch[] = [];\n // Detect nested quantifiers in regex\n const patterns = [\n /new\\s+RegExp\\s*\\(\\s*[\"'`].*\\([^)]*[+*]\\)[+*{]/g,\n /\\/.*\\([^)]*[+*]\\)[+*{].*\\//g,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, regexDos, filePath, () =>\n \"Avoid nested quantifiers in regex. Use atomic groups, possessive quantifiers, or the 're2' library for safe regex execution.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC081 – XML External Entity (XXE)\n// ────────────────────────────────────────────\n\nconst xxeVulnerability: CustomRule = {\n id: \"VC081\",\n title: \"XML External Entity (XXE) Injection\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"XML parsers that process external entities allow attackers to read files, perform SSRF, or cause DoS via billion-laughs attacks.\",\n check(content, filePath) {\n if (!/xml|parseXML|DOMParser|SAXParser|etree|lxml/i.test(content)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /\\.parseXML\\s*\\(/g,\n /new\\s+DOMParser\\s*\\(\\)/g,\n /etree\\.parse\\s*\\(/g,\n /lxml\\.etree/g,\n /SAXParserFactory/g,\n /XMLReaderFactory/g,\n ];\n const hasProtection = /noent.*false|resolveExternals.*false|FEATURE_EXTERNAL.*false|defusedxml|disallow-doctype-decl/i.test(content);\n if (hasProtection) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, xxeVulnerability, filePath, () =>\n \"Disable external entities: set noent: false, or use defusedxml (Python). For Java: factory.setFeature('http://apache.org/xml/features/disallow-doctype-decl', true).\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC082 – Server-Side Template Injection\n// ────────────────────────────────────────────\n\nconst ssti: CustomRule = {\n id: \"VC082\",\n title: \"Server-Side Template Injection (SSTI)\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"Rendering templates from user-controlled strings allows attackers to execute arbitrary code on the server.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /render_template_string\\s*\\(\\s*(?![\"'`])/g,\n /Template\\s*\\(\\s*(?:req\\.|body\\.|input|params|args|user)/gi,\n /engine\\.render\\s*\\(\\s*(?:req\\.|body\\.|input)/gi,\n /nunjucks\\.renderString\\s*\\(\\s*(?:req\\.|body\\.|input)/gi,\n /ejs\\.render\\s*\\(\\s*(?:req\\.|body\\.|input)/gi,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, ssti, filePath, () =>\n \"Never render templates from user input. Use pre-defined templates and pass data as context variables: render_template('template.html', data=user_data).\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC083 – Insecure Java Deserialization\n// ────────────────────────────────────────────\n\nconst javaDeserialization: CustomRule = {\n id: \"VC083\",\n title: \"Insecure Java Deserialization\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"ObjectInputStream.readObject() on untrusted data allows arbitrary code execution via gadget chains in the classpath.\",\n check(content, filePath) {\n if (!filePath.match(/\\.java$|\\.kt$/)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /ObjectInputStream\\s*\\(/g,\n /\\.readObject\\s*\\(\\)/g,\n /XMLDecoder\\s*\\(/g,\n /XStream\\s*\\(\\)/g,\n ];\n const hasSafe = /ValidatingObjectInputStream|ObjectInputFilter|SerialKiller|NotSerializableException/i.test(content);\n if (hasSafe) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, javaDeserialization, filePath, () =>\n \"Use ValidatingObjectInputStream with an allowlist of classes, or avoid Java serialization entirely. Use JSON instead.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC084 – Missing Subresource Integrity (SRI)\n// ────────────────────────────────────────────\n\nconst missingSRI: CustomRule = {\n id: \"VC084\",\n title: \"Missing Subresource Integrity (SRI)\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"External scripts and stylesheets loaded without integrity= attributes can be tampered with if the CDN is compromised.\",\n check(content, filePath) {\n if (!filePath.match(/\\.(html|htm|jsx|tsx|ejs|hbs)$/)) return [];\n const matches: RuleMatch[] = [];\n // Script tags with external src but no integrity\n const scriptPattern = /<script\\s+[^>]*src\\s*=\\s*[\"']https?:\\/\\/[^\"']+[\"'][^>]*>/gi;\n let m: RegExpExecArray | null;\n const re = new RegExp(scriptPattern.source, scriptPattern.flags);\n while ((m = re.exec(content)) !== null) {\n if (!m[0].includes(\"integrity\")) {\n const lineNum = content.substring(0, m.index).split(\"\\n\").length;\n matches.push({\n rule: \"VC084\", title: missingSRI.title, severity: \"medium\", category: \"Configuration\",\n file: filePath, line: lineNum, snippet: getSnippet(content, lineNum),\n fix: 'Add integrity and crossorigin attributes: <script src=\"...\" integrity=\"sha384-...\" crossorigin=\"anonymous\">'\n });\n }\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC085 – Exposed Admin/Debug Routes\n// ────────────────────────────────────────────\n\nconst exposedAdminRoutes: CustomRule = {\n id: \"VC085\",\n title: \"Exposed Admin or Debug Route\",\n severity: \"high\",\n category: \"Information Leakage\",\n description: \"Routes like /admin, /debug, /phpinfo, or /actuator without authentication expose sensitive controls and information to attackers.\",\n check(content, filePath) {\n if (!/(?:\\/api\\/|routes?\\/|server\\.|app\\.|index\\.[jt]s)/i.test(filePath)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /[.'\"]\\s*(?:get|use|all)\\s*\\(\\s*[\"'`]\\/(?:admin|debug|_debug|__debug__|phpinfo|actuator|graphiql|playground|swagger)[\"'`]/gi,\n ];\n const hasAuth = /auth|requireAuth|isAdmin|requireAdmin|authenticate|middleware.*admin/i.test(content);\n if (hasAuth) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, exposedAdminRoutes, filePath, () =>\n \"Protect admin/debug routes with authentication middleware. In production, disable debug endpoints entirely.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC086 – Insecure WebSocket\n// ────────────────────────────────────────────\n\nconst insecureWebSocket: CustomRule = {\n id: \"VC086\",\n title: \"Insecure WebSocket Connection (ws://)\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Using ws:// instead of wss:// transmits data in plaintext, vulnerable to eavesdropping and man-in-the-middle attacks.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n return findMatches(content, /new\\s+WebSocket\\s*\\(\\s*[\"'`]ws:\\/\\//g, insecureWebSocket, filePath, () =>\n \"Use wss:// (WebSocket Secure) instead of ws:// for encrypted connections: new WebSocket('wss://...').\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC087 – Missing HSTS\n// ────────────────────────────────────────────\n\nconst missingHSTS: CustomRule = {\n id: \"VC087\",\n title: \"Missing HTTP Strict Transport Security (HSTS)\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Without HSTS headers, browsers allow downgrade attacks from HTTPS to HTTP, exposing traffic to interception.\",\n check(content, filePath) {\n if (!/(?:server|app|index|main)\\.[jt]sx?$/.test(filePath)) return [];\n if (!/(?:express|hono|fastify|koa)/i.test(content)) return [];\n if (/Strict-Transport-Security|hsts|helmet/i.test(content)) return [];\n return findMatches(content, /(?:express|hono|fastify|koa)\\s*\\(/gi, missingHSTS, filePath, () =>\n \"Add HSTS header: res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains'). Or use helmet().\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC088 – Sensitive Data in URL Parameters\n// ────────────────────────────────────────────\n\nconst sensitiveURLParams: CustomRule = {\n id: \"VC088\",\n title: \"Sensitive Data in URL Parameters\",\n severity: \"high\",\n category: \"Information Leakage\",\n description: \"Passing passwords, tokens, or API keys in URL query parameters exposes them in server logs, browser history, and referrer headers.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /\\?\\s*(?:password|token|secret|api_key|apiKey|access_token|ssn|credit_card)\\s*=/gi,\n /[&?](?:password|token|secret|api_key|apiKey|access_token)\\s*=\\s*\\$\\{/gi,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, sensitiveURLParams, filePath, () =>\n \"Never pass sensitive data in URL parameters. Use request headers (Authorization: Bearer ...) or POST body instead.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC089 – Missing Content-Disposition\n// ────────────────────────────────────────────\n\nconst missingContentDisposition: CustomRule = {\n id: \"VC089\",\n title: \"File Download Missing Content-Disposition\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"File download endpoints without Content-Disposition headers may render files inline, leading to XSS if the file contains HTML/JS.\",\n check(content, filePath) {\n if (!/(?:download|sendFile|send_file|pipe|createReadStream)/i.test(content)) return [];\n if (!/(?:\\/api\\/|routes?\\/|controllers?\\/|server\\.|handler)/i.test(filePath)) return [];\n if (/Content-Disposition|attachment|download/i.test(content)) return [];\n return findMatches(content, /(?:sendFile|send_file|createReadStream|\\.pipe)\\s*\\(/gi, missingContentDisposition, filePath, () =>\n \"Set Content-Disposition: attachment header on file downloads: res.setHeader('Content-Disposition', 'attachment; filename=\\\"file.pdf\\\"').\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC090 – Open Redirect via Host Header\n// ────────────────────────────────────────────\n\nconst hostHeaderRedirect: CustomRule = {\n id: \"VC090\",\n title: \"Open Redirect via Host Header\",\n severity: \"high\",\n category: \"Injection\",\n description: \"Using req.headers.host to construct redirect URLs allows attackers to inject a malicious host header, redirecting users to phishing sites.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n const matches: RuleMatch[] = [];\n if (/req\\.headers\\.host|req\\.get\\s*\\(\\s*[\"']host[\"']\\)/i.test(content) && /redirect|location/i.test(content)) {\n matches.push(...findMatches(content, /req\\.headers\\.host|req\\.get\\s*\\(\\s*[\"']host[\"']\\)/gi, hostHeaderRedirect, filePath, () =>\n \"Don't use req.headers.host for redirects — it's attacker-controlled. Use a hardcoded domain or environment variable.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC091 – Race Condition / TOCTOU\n// ────────────────────────────────────────────\n\nconst raceCondition: CustomRule = {\n id: \"VC091\",\n title: \"Potential Race Condition (TOCTOU)\",\n severity: \"high\",\n category: \"Authorization\",\n description: \"Check-then-act patterns (e.g., checking if a file exists then writing to it) are vulnerable to race conditions where state changes between the check and the action.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /(?:existsSync|exists)\\s*\\([^)]+\\)[\\s\\S]{0,50}(?:writeFileSync|writeFile|unlinkSync|unlink|renameSync)\\s*\\(/g,\n /os\\.path\\.exists\\s*\\([^)]+\\)[\\s\\S]{0,50}open\\s*\\(/g,\n /File\\.exists\\?\\s*\\([^)]+\\)[\\s\\S]{0,50}File\\.(?:write|delete)/g,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, raceCondition, filePath, () =>\n \"Use atomic operations instead of check-then-act. For files: use fs.open with 'wx' flag (exclusive create), or use file locks.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC092 – Unsafe Object.assign from User Input\n// ────────────────────────────────────────────\n\nconst unsafeObjectAssign: CustomRule = {\n id: \"VC092\",\n title: \"Unsafe Object Spread from User Input\",\n severity: \"medium\",\n category: \"Injection\",\n description: \"Spreading request body into a new object can copy __proto__, constructor, or other dangerous properties, enabling prototype pollution.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /Object\\.assign\\s*\\(\\s*\\{\\s*\\}\\s*,\\s*(?:req\\.(?:body|query|params)|body|input)\\s*\\)/gi,\n /\\{\\s*\\.\\.\\.(?:req\\.(?:body|query|params)|body|input)\\s*\\}/gi,\n ];\n const hasSafe = /omit.*__proto__|sanitize|pick\\(|lodash\\.pick|stripProto/i.test(content);\n if (hasSafe) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, unsafeObjectAssign, filePath, () =>\n \"Explicitly pick allowed properties instead of spreading: const { name, email } = req.body; const safe = { name, email };\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC093 – Unprotected File Download Endpoint\n// ────────────────────────────────────────────\n\nconst unprotectedDownload: CustomRule = {\n id: \"VC093\",\n title: \"File Download Without Path Validation\",\n severity: \"medium\",\n category: \"Authorization\",\n description: \"File download endpoints that accept user-controlled filenames without path validation allow directory traversal to read arbitrary files.\",\n check(content, filePath) {\n if (!/(?:download|sendFile|send_file)/i.test(content)) return [];\n if (!/(?:\\/api\\/|routes?\\/|controllers?\\/|server\\.|handler)/i.test(filePath)) return [];\n const matches: RuleMatch[] = [];\n // sendFile/download with user input\n if (/(?:sendFile|download|send_file)\\s*\\([^)]*(?:req\\.|params\\.|query\\.|body\\.)/i.test(content)) {\n const hasValidation = /path\\.resolve|path\\.normalize|path\\.join.*__dirname|realpath|includes\\s*\\(\\s*[\"']\\.\\./i.test(content);\n if (!hasValidation) {\n matches.push(...findMatches(content, /(?:sendFile|download|send_file)\\s*\\(/gi, unprotectedDownload, filePath, () =>\n \"Validate file paths: const safePath = path.resolve(DOWNLOAD_DIR, filename); if (!safePath.startsWith(DOWNLOAD_DIR)) throw new Error('Invalid path');\"\n ));\n }\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC094 – Command Injection\n// ────────────────────────────────────────────\n\nconst commandInjection: CustomRule = {\n id: \"VC094\",\n title: \"Potential Command Injection\",\n severity: \"critical\",\n category: \"Injection\",\n description: \"Passing user input to shell commands (exec, system, child_process) allows attackers to execute arbitrary system commands.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\")) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n // Node.js\n /(?:exec|execSync)\\s*\\(\\s*(?:`[^`]*\\$\\{|[\"'][^\"']*\\+\\s*(?:req\\.|body\\.|input|params|args|user))/gi,\n /child_process.*exec\\s*\\(\\s*(?![\"'`])/g,\n // Python\n /os\\.system\\s*\\(\\s*(?![\"'`].*[\"'`]\\s*\\))/g,\n /subprocess\\.(?:call|run|Popen)\\s*\\([^)]*shell\\s*=\\s*True/gi,\n // Ruby\n /system\\s*\\(\\s*[\"'].*#\\{/g,\n ];\n const hasSafe = /execFile|spawn|escapeshellarg|shlex\\.quote|shellEscape/i.test(content);\n if (hasSafe) return [];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, commandInjection, filePath, () =>\n \"Use execFile/spawn instead of exec (avoids shell). Never concatenate user input into shell commands. Use parameterized arguments.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC095 – Hardcoded CORS Origin Localhost\n// ────────────────────────────────────────────\n\nconst corsLocalhost: CustomRule = {\n id: \"VC095\",\n title: \"Hardcoded Localhost CORS Origin\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Hardcoded localhost CORS origins in production code allow any local process to make authenticated requests to your API.\",\n check(content, filePath) {\n if (filePath.includes(\"test\") || filePath.includes(\"mock\") || filePath.includes(\".env\")) return [];\n if (!/origin/i.test(content)) return [];\n return findMatches(content, /origin\\s*[:=]\\s*[\"'`]http:\\/\\/localhost/gi, corsLocalhost, filePath, () =>\n \"Use environment variables for CORS origins: origin: process.env.ALLOWED_ORIGIN. Remove localhost from production configs.\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC096 – Unencrypted gRPC\n// ────────────────────────────────────────────\n\nconst insecureGRPC: CustomRule = {\n id: \"VC096\",\n title: \"Unencrypted gRPC Channel\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Using insecure gRPC channels transmits data including credentials in plaintext.\",\n check(content, filePath) {\n if (!/grpc/i.test(content)) return [];\n return findMatches(content, /(?:insecure_channel|createInsecure|grpc\\.Insecure)/gi, insecureGRPC, filePath, () =>\n \"Use encrypted gRPC channels: grpc.ssl_channel_credentials() or grpc.credentials.createSsl().\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// COMPLIANCE MAPPING (OWASP Top 10 + CWE)\n// ────────────────────────────────────────────\n\nexport const complianceMap: Record<string, { owasp: string; cwe: string }> = {\n VC001: { owasp: \"A07:2021\", cwe: \"CWE-798\" },\n VC002: { owasp: \"A05:2021\", cwe: \"CWE-200\" },\n VC003: { owasp: \"A01:2021\", cwe: \"CWE-862\" },\n VC004: { owasp: \"A01:2021\", cwe: \"CWE-284\" },\n VC005: { owasp: \"A08:2021\", cwe: \"CWE-345\" },\n VC006: { owasp: \"A03:2021\", cwe: \"CWE-89\" },\n VC007: { owasp: \"A03:2021\", cwe: \"CWE-79\" },\n VC008: { owasp: \"A04:2021\", cwe: \"CWE-770\" },\n VC009: { owasp: \"A05:2021\", cwe: \"CWE-942\" },\n VC010: { owasp: \"A01:2021\", cwe: \"CWE-602\" },\n VC011: { owasp: \"A07:2021\", cwe: \"CWE-798\" },\n VC012: { owasp: \"A05:2021\", cwe: \"CWE-200\" },\n VC013: { owasp: \"A01:2021\", cwe: \"CWE-269\" },\n VC014: { owasp: \"A05:2021\", cwe: \"CWE-538\" },\n VC015: { owasp: \"A03:2021\", cwe: \"CWE-95\" },\n VC016: { owasp: \"A01:2021\", cwe: \"CWE-601\" },\n VC017: { owasp: \"A05:2021\", cwe: \"CWE-614\" },\n VC018: { owasp: \"A07:2021\", cwe: \"CWE-798\" },\n VC019: { owasp: \"A05:2021\", cwe: \"CWE-693\" },\n VC020: { owasp: \"A05:2021\", cwe: \"CWE-1021\" },\n VC021: { owasp: \"A01:2021\", cwe: \"CWE-22\" },\n VC022: { owasp: \"A03:2021\", cwe: \"CWE-79\" },\n VC023: { owasp: \"A08:2021\", cwe: \"CWE-1321\" },\n VC024: { owasp: \"A04:2021\", cwe: \"CWE-770\" },\n VC025: { owasp: \"A03:2021\", cwe: \"CWE-22\" },\n VC026: { owasp: \"A05:2021\", cwe: \"CWE-693\" },\n VC027: { owasp: \"A05:2021\", cwe: \"CWE-693\" },\n VC028: { owasp: \"A07:2021\", cwe: \"CWE-20\" },\n VC029: { owasp: \"A08:2021\", cwe: \"CWE-20\" },\n VC030: { owasp: \"A08:2021\", cwe: \"CWE-502\" },\n VC031: { owasp: \"A02:2021\", cwe: \"CWE-321\" },\n VC032: { owasp: \"A05:2021\", cwe: \"CWE-319\" },\n VC033: { owasp: \"A05:2021\", cwe: \"CWE-215\" },\n VC034: { owasp: \"A02:2021\", cwe: \"CWE-338\" },\n VC035: { owasp: \"A01:2021\", cwe: \"CWE-601\" },\n VC036: { owasp: \"A04:2021\", cwe: \"CWE-755\" },\n VC037: { owasp: \"A09:2021\", cwe: \"CWE-209\" },\n VC038: { owasp: \"A04:2021\", cwe: \"CWE-434\" },\n VC039: { owasp: \"A06:2021\", cwe: \"CWE-1104\" },\n VC040: { owasp: \"A05:2021\", cwe: \"CWE-538\" },\n VC041: { owasp: \"A10:2021\", cwe: \"CWE-918\" },\n VC042: { owasp: \"A01:2021\", cwe: \"CWE-915\" },\n VC043: { owasp: \"A02:2021\", cwe: \"CWE-208\" },\n VC044: { owasp: \"A09:2021\", cwe: \"CWE-117\" },\n VC045: { owasp: \"A07:2021\", cwe: \"CWE-521\" },\n VC046: { owasp: \"A07:2021\", cwe: \"CWE-384\" },\n VC047: { owasp: \"A07:2021\", cwe: \"CWE-307\" },\n VC048: { owasp: \"A03:2021\", cwe: \"CWE-943\" },\n VC049: { owasp: \"A07:2021\", cwe: \"CWE-798\" },\n VC050: { owasp: \"A02:2021\", cwe: \"CWE-319\" },\n VC051: { owasp: \"A05:2021\", cwe: \"CWE-200\" },\n VC052: { owasp: \"A04:2021\", cwe: \"CWE-770\" },\n VC053: { owasp: \"A05:2021\", cwe: \"CWE-798\" },\n VC054: { owasp: \"A07:2021\", cwe: \"CWE-922\" },\n VC055: { owasp: \"A05:2021\", cwe: \"CWE-540\" },\n VC056: { owasp: \"A05:2021\", cwe: \"CWE-1021\" },\n VC057: { owasp: \"A01:2021\", cwe: \"CWE-269\" },\n VC058: { owasp: \"A05:2021\", cwe: \"CWE-250\" },\n VC059: { owasp: \"A05:2021\", cwe: \"CWE-284\" },\n VC060: { owasp: \"A02:2021\", cwe: \"CWE-328\" },\n VC061: { owasp: \"A02:2021\", cwe: \"CWE-295\" },\n VC062: { owasp: \"A02:2021\", cwe: \"CWE-321\" },\n VC063: { owasp: \"A03:2021\", cwe: \"CWE-79\" },\n VC064: { owasp: \"A01:2021\", cwe: \"CWE-862\" },\n VC065: { owasp: \"A01:2021\", cwe: \"CWE-862\" },\n VC066: { owasp: \"A07:2021\", cwe: \"CWE-798\" },\n VC067: { owasp: \"A01:2021\", cwe: \"CWE-601\" },\n VC068: { owasp: \"A07:2021\", cwe: \"CWE-922\" },\n VC069: { owasp: \"A02:2021\", cwe: \"CWE-295\" },\n VC070: { owasp: \"A05:2021\", cwe: \"CWE-489\" },\n VC071: { owasp: \"A05:2021\", cwe: \"CWE-215\" },\n VC072: { owasp: \"A07:2021\", cwe: \"CWE-798\" },\n VC073: { owasp: \"A08:2021\", cwe: \"CWE-502\" },\n VC074: { owasp: \"A01:2021\", cwe: \"CWE-352\" },\n VC075: { owasp: \"A03:2021\", cwe: \"CWE-78\" },\n VC076: { owasp: \"A07:2021\", cwe: \"CWE-798\" },\n VC077: { owasp: \"A05:2021\", cwe: \"CWE-942\" },\n VC078: { owasp: \"A05:2021\", cwe: \"CWE-250\" },\n VC079: { owasp: \"A02:2021\", cwe: \"CWE-327\" },\n VC080: { owasp: \"A04:2021\", cwe: \"CWE-1333\" },\n VC081: { owasp: \"A03:2021\", cwe: \"CWE-611\" },\n VC082: { owasp: \"A03:2021\", cwe: \"CWE-94\" },\n VC083: { owasp: \"A08:2021\", cwe: \"CWE-502\" },\n VC084: { owasp: \"A06:2021\", cwe: \"CWE-353\" },\n VC085: { owasp: \"A01:2021\", cwe: \"CWE-862\" },\n VC086: { owasp: \"A02:2021\", cwe: \"CWE-319\" },\n VC087: { owasp: \"A05:2021\", cwe: \"CWE-311\" },\n VC088: { owasp: \"A07:2021\", cwe: \"CWE-598\" },\n VC089: { owasp: \"A05:2021\", cwe: \"CWE-430\" },\n VC090: { owasp: \"A01:2021\", cwe: \"CWE-601\" },\n VC091: { owasp: \"A04:2021\", cwe: \"CWE-367\" },\n VC092: { owasp: \"A08:2021\", cwe: \"CWE-1321\" },\n VC093: { owasp: \"A01:2021\", cwe: \"CWE-22\" },\n VC094: { owasp: \"A03:2021\", cwe: \"CWE-78\" },\n VC095: { owasp: \"A05:2021\", cwe: \"CWE-942\" },\n VC096: { owasp: \"A02:2021\", cwe: \"CWE-319\" },\n};\n\n// ────────────────────────────────────────────\n// VC097 – Console.log in Production\n// ────────────────────────────────────────────\n\nconst consoleLogProduction: CustomRule = {\n id: \"VC097\",\n title: \"Console.log Left in Production Code\",\n severity: \"medium\",\n category: \"Performance\",\n description: \"console.log statements left in production code can leak sensitive data, slow down rendering, and clutter browser consoles.\",\n check(content, filePath) {\n if (filePath.match(/test|spec|mock|__tests__|fixture|\\.test\\.|\\.spec\\./i)) return [];\n if (!/console\\.log\\s*\\(/g.test(content)) return [];\n const lines = content.split(\"\\n\");\n const matches: RuleMatch[] = [];\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n if (/console\\.log\\s*\\(/.test(line) && !line.startsWith(\"//\") && !line.startsWith(\"*\") && !/if\\s*\\(\\s*(?:debug|process\\.env)/i.test(lines[Math.max(0, i-1)] + line)) {\n matches.push({ rule: \"VC097\", title: consoleLogProduction.title, severity: \"medium\" as const, category: \"Performance\", file: filePath, line: i + 1, snippet: getSnippet(content, i + 1), fix: \"Remove console.log or use a logger that can be disabled in production.\" });\n }\n }\n return matches.slice(0, 3); // Limit to 3 per file\n },\n};\n\n// ────────────────────────────────────────────\n// VC098 – Synchronous File Operations\n// ────────────────────────────────────────────\n\nconst syncFileOps: CustomRule = {\n id: \"VC098\",\n title: \"Synchronous File Operations\",\n severity: \"medium\",\n category: \"Performance\",\n description: \"Synchronous file operations (readFileSync, writeFileSync) block the event loop, causing all other requests to wait.\",\n check(content, filePath) {\n if (filePath.match(/test|spec|mock|__tests__|fixture|config|\\.config\\./i)) return [];\n return findMatches(content, /(?:readFileSync|writeFileSync|appendFileSync|mkdirSync|rmdirSync|statSync)\\s*\\(/g, syncFileOps, filePath, () =>\n \"Use async file operations (readFile, writeFile) to avoid blocking the event loop.\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC099 – Memory Leak: Event Listener\n// ────────────────────────────────────────────\n\nconst eventListenerLeak: CustomRule = {\n id: \"VC099\",\n title: \"Memory Leak: Event Listener Not Cleaned Up\",\n severity: \"high\",\n category: \"Performance\",\n description: \"Adding event listeners in React useEffect without a cleanup function causes memory leaks as listeners accumulate on re-renders.\",\n check(content, filePath) {\n if (!filePath.match(/\\.(jsx|tsx)$/)) return [];\n if (!/addEventListener/i.test(content)) return [];\n if (/removeEventListener/i.test(content)) return [];\n if (!/useEffect/i.test(content)) return [];\n return findMatches(content, /addEventListener\\s*\\(/g, eventListenerLeak, filePath, () =>\n \"Return a cleanup function from useEffect: useEffect(() => { window.addEventListener('resize', fn); return () => window.removeEventListener('resize', fn); }, []);\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC100 – N+1 Query Pattern\n// ────────────────────────────────────────────\n\nconst nPlusOneQuery: CustomRule = {\n id: \"VC100\",\n title: \"N+1 Query Pattern Detected\",\n severity: \"medium\",\n category: \"Performance\",\n description: \"Database queries inside loops cause N+1 performance problems — one query per iteration instead of a single batch query.\",\n check(content, filePath) {\n if (filePath.match(/test|spec|mock/i)) return [];\n const hasLoopWithQuery = /(?:for\\s*\\(|\\.forEach\\s*\\(|\\.map\\s*\\(|while\\s*\\()[^}]*(?:\\.find\\(|\\.findOne\\(|\\.findById\\(|\\.query\\(|\\.execute\\(|SELECT\\s)/is.test(content);\n if (!hasLoopWithQuery) return [];\n return findMatches(content, /(?:for\\s*\\(|\\.forEach\\s*\\(|\\.map\\s*\\(|while\\s*\\()/g, nPlusOneQuery, filePath, () =>\n \"Fetch all data in a single query using WHERE IN, JOIN, or batch operations instead of querying per item in a loop.\"\n ).slice(0, 2);\n },\n};\n\n// ────────────────────────────────────────────\n// VC101 – Large Bundle Import\n// ────────────────────────────────────────────\n\nconst largeBundleImport: CustomRule = {\n id: \"VC101\",\n title: \"Importing Entire Library (Large Bundle)\",\n severity: \"medium\",\n category: \"Performance\",\n description: \"Importing entire libraries like lodash or moment.js adds hundreds of KB to your bundle. Import only the functions you need.\",\n check(content, filePath) {\n if (!filePath.match(/\\.(jsx?|tsx?)$/)) return [];\n const matches: RuleMatch[] = [];\n const patterns = [\n /import\\s+_\\s+from\\s+['\"]lodash['\"]/g,\n /import\\s+\\*\\s+as\\s+_\\s+from\\s+['\"]lodash['\"]/g,\n /import\\s+moment\\s+from\\s+['\"]moment['\"]/g,\n /const\\s+_\\s*=\\s*require\\s*\\(\\s*['\"]lodash['\"]\\s*\\)/g,\n /const\\s+moment\\s*=\\s*require\\s*\\(\\s*['\"]moment['\"]\\s*\\)/g,\n ];\n for (const p of patterns) {\n matches.push(...findMatches(content, p, largeBundleImport, filePath, () =>\n \"Import only what you need: import { debounce } from 'lodash/debounce'. Or switch to lighter alternatives like date-fns instead of moment.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC102 – Blocking Main Thread\n// ────────────────────────────────────────────\n\nconst blockingMainThread: CustomRule = {\n id: \"VC102\",\n title: \"Blocking Main Thread with Heavy Computation\",\n severity: \"medium\",\n category: \"Performance\",\n description: \"Infinite loops or deeply nested iterations on the main thread freeze the UI and cause unresponsiveness.\",\n check(content, filePath) {\n if (filePath.match(/worker|test|spec|mock/i)) return [];\n const matches: RuleMatch[] = [];\n if (/while\\s*\\(\\s*true\\s*\\)/g.test(content)) {\n matches.push(...findMatches(content, /while\\s*\\(\\s*true\\s*\\)/g, blockingMainThread, filePath, () =>\n \"Avoid while(true) on the main thread. Use Web Workers for heavy computation or requestIdleCallback for non-urgent work.\"\n ));\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC103 – TODO/FIXME Left in Code\n// ────────────────────────────────────────────\n\nconst todoLeftInCode: CustomRule = {\n id: \"VC103\",\n title: \"TODO/FIXME Left in Code\",\n severity: \"low\",\n category: \"Code Quality\",\n description: \"TODO, FIXME, HACK, and XXX comments indicate unfinished work that should be resolved before shipping to production.\",\n check(content, filePath) {\n if (filePath.match(/test|spec|mock|__tests__|fixture|node_modules/i)) return [];\n return findMatches(content, /\\/\\/\\s*(?:TODO|FIXME|HACK|XXX)\\b/gi, todoLeftInCode, filePath, () =>\n \"Resolve TODO/FIXME comments before shipping. If it's intentional tech debt, track it in your issue tracker instead.\"\n ).slice(0, 5);\n },\n};\n\n// ────────────────────────────────────────────\n// VC104 – Empty Catch Block\n// ────────────────────────────────────────────\n\nconst emptyCatchBlock: CustomRule = {\n id: \"VC104\",\n title: \"Empty Catch Block\",\n severity: \"medium\",\n category: \"Code Quality\",\n description: \"Empty catch blocks silently swallow errors, making bugs impossible to diagnose. At minimum, log the error.\",\n check(content, filePath) {\n if (filePath.match(/test|spec|mock/i)) return [];\n return findMatches(content, /catch\\s*(?:\\([^)]*\\))?\\s*\\{\\s*\\}/g, emptyCatchBlock, filePath, () =>\n \"Handle errors in catch blocks: catch(err) { console.error('Operation failed:', err); } or re-throw if appropriate.\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC105 – Callback Hell\n// ────────────────────────────────────────────\n\nconst callbackHell: CustomRule = {\n id: \"VC105\",\n title: \"Deeply Nested Callbacks (Promise Chain)\",\n severity: \"medium\",\n category: \"Code Quality\",\n description: \"Long .then() chains or deeply nested callbacks are hard to read, debug, and maintain. Refactor to async/await.\",\n check(content, filePath) {\n if (filePath.match(/test|spec|mock/i)) return [];\n return findMatches(content, /\\.then\\s*\\([^)]*\\)\\s*\\.then\\s*\\([^)]*\\)\\s*\\.then/g, callbackHell, filePath, () =>\n \"Refactor .then() chains to async/await for cleaner, more readable code.\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC106 – Magic Numbers\n// ────────────────────────────────────────────\n\nconst magicNumbers: CustomRule = {\n id: \"VC106\",\n title: \"Magic Numbers in Code\",\n severity: \"low\",\n category: \"Code Quality\",\n description: \"Unnamed numeric constants in conditions or calculations make code hard to understand. Extract them into named constants.\",\n check(content, filePath) {\n if (filePath.match(/test|spec|mock|config|\\.config\\.|constant|enum|migration/i)) return [];\n if (!filePath.match(/\\.(jsx?|tsx?)$/)) return [];\n const matches: RuleMatch[] = [];\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n if (line.startsWith(\"//\") || line.startsWith(\"*\")) continue;\n // Look for conditions with magic numbers > 1 (skip 0, 1, -1, 2)\n if (/(?:===|!==|>=?|<=?)\\s*\\d{3,}/.test(line) || /(?:setTimeout|setInterval)\\s*\\([^,]+,\\s*\\d{4,}/.test(line)) {\n matches.push({ rule: \"VC106\", title: magicNumbers.title, severity: \"low\" as const, category: \"Code Quality\", file: filePath, line: i + 1, snippet: getSnippet(content, i + 1), fix: \"Extract magic numbers into named constants: const MAX_RETRIES = 3; const TIMEOUT_MS = 5000;\" });\n }\n }\n return matches.slice(0, 3);\n },\n};\n\n// ────────────────────────────────────────────\n// VC107 – S3 Bucket Without Encryption\n// ────────────────────────────────────────────\n\nconst s3BucketNoEncryption: CustomRule = {\n id: \"VC107\",\n title: \"S3 Bucket Without Encryption\",\n severity: \"high\",\n category: \"Infrastructure\",\n description: \"AWS S3 buckets without server-side encryption leave data at rest unprotected. Enable encryption to protect sensitive data.\",\n check(content, filePath) {\n if (!filePath.match(/\\.tf$/)) return [];\n if (!/resource\\s+\"aws_s3_bucket\"/.test(content)) return [];\n const matches: RuleMatch[] = [];\n // Find S3 bucket resources without encryption configuration nearby\n const bucketPattern = /resource\\s+\"aws_s3_bucket\"\\s+\"(\\w+)\"/g;\n let m: RegExpExecArray | null;\n while ((m = bucketPattern.exec(content)) !== null) {\n if (isCommentLine(content, m.index)) continue;\n // Check if there's a server_side_encryption_configuration within a reasonable range\n const blockEnd = Math.min(m.index + 2000, content.length);\n const blockContent = content.substring(m.index, blockEnd);\n if (!/server_side_encryption/.test(blockContent)) {\n const lineNum = content.substring(0, m.index).split(\"\\n\").length;\n matches.push({\n rule: \"VC107\", title: s3BucketNoEncryption.title, severity: \"high\" as const, category: \"Infrastructure\",\n file: filePath, line: lineNum, snippet: getSnippet(content, lineNum),\n fix: \"Enable S3 bucket encryption: server_side_encryption_configuration { rule { apply_server_side_encryption_by_default { sse_algorithm = 'aws:kms' } } }\",\n });\n }\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC108 – Security Group Allows All Inbound\n// ────────────────────────────────────────────\n\nconst securityGroupAllInbound: CustomRule = {\n id: \"VC108\",\n title: \"Security Group Allows All Inbound\",\n severity: \"critical\",\n category: \"Infrastructure\",\n description: \"Security groups allowing all inbound traffic (0.0.0.0/0 on all ports) expose resources to the entire internet.\",\n check(content, filePath) {\n if (!filePath.match(/\\.(tf|json|yaml|yml)$/)) return [];\n const matches: RuleMatch[] = [];\n // Terraform: ingress with 0.0.0.0/0 and port 0 or no port restriction\n if (filePath.match(/\\.tf$/)) {\n const ingressPattern = /ingress\\s*\\{[^}]*cidr_blocks\\s*=\\s*\\[\\s*\"0\\.0\\.0\\.0\\/0\"\\s*\\][^}]*\\}/gs;\n let m: RegExpExecArray | null;\n while ((m = ingressPattern.exec(content)) !== null) {\n if (isCommentLine(content, m.index)) continue;\n // Check for unrestricted ports (from_port = 0 or no port spec)\n if (/from_port\\s*=\\s*0/.test(m[0]) || !/from_port/.test(m[0])) {\n const lineNum = content.substring(0, m.index).split(\"\\n\").length;\n matches.push({\n rule: \"VC108\", title: securityGroupAllInbound.title, severity: \"critical\" as const, category: \"Infrastructure\",\n file: filePath, line: lineNum, snippet: getSnippet(content, lineNum),\n fix: \"Restrict security group ingress to specific IP ranges and ports.\",\n });\n }\n }\n }\n // CloudFormation: AWS::EC2::SecurityGroup with CidrIp: 0.0.0.0/0\n if (filePath.match(/\\.(json|yaml|yml)$/)) {\n const cfnPattern = /AWS::EC2::SecurityGroup/g;\n if (cfnPattern.test(content) && /CidrIp\\s*:\\s*[\"']?0\\.0\\.0\\.0\\/0/.test(content)) {\n matches.push(...findMatches(content, /CidrIp\\s*:\\s*[\"']?0\\.0\\.0\\.0\\/0/g, securityGroupAllInbound, filePath, () =>\n \"Restrict security group ingress to specific IP ranges and ports.\"\n ));\n }\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC109 – RDS Instance Publicly Accessible\n// ────────────────────────────────────────────\n\nconst rdsPubliclyAccessible: CustomRule = {\n id: \"VC109\",\n title: \"RDS Instance Publicly Accessible\",\n severity: \"critical\",\n category: \"Infrastructure\",\n description: \"RDS instances with publicly_accessible = true are exposed to the internet, risking unauthorized database access.\",\n check(content, filePath) {\n if (!filePath.match(/\\.tf$/)) return [];\n if (!/resource\\s+\"aws_db_instance\"/.test(content)) return [];\n return findMatches(content, /publicly_accessible\\s*=\\s*true/g, rdsPubliclyAccessible, filePath, () =>\n \"Set publicly_accessible = false. Access RDS through VPC private subnets.\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC110 – Missing CloudTrail Logging\n// ────────────────────────────────────────────\n\nconst missingCloudTrail: CustomRule = {\n id: \"VC110\",\n title: \"Missing CloudTrail Logging\",\n severity: \"high\",\n category: \"Infrastructure\",\n description: \"AWS environments without CloudTrail lack audit logging of API calls, making it difficult to detect unauthorized activity.\",\n check(content, filePath) {\n if (!filePath.match(/\\.tf$/)) return [];\n // Only flag if the file uses AWS provider but has no cloudtrail resource\n if (!/provider\\s+\"aws\"/.test(content)) return [];\n if (/aws_cloudtrail/.test(content)) return [];\n const lineNum = content.substring(0, content.search(/provider\\s+\"aws\"/)).split(\"\\n\").length;\n return [{\n rule: \"VC110\", title: missingCloudTrail.title, severity: \"high\" as const, category: \"Infrastructure\",\n file: filePath, line: lineNum, snippet: getSnippet(content, lineNum),\n fix: \"Enable CloudTrail for audit logging of all AWS API calls.\",\n }];\n },\n};\n\n// ────────────────────────────────────────────\n// VC111 – Lambda Without VPC\n// ────────────────────────────────────────────\n\nconst lambdaWithoutVPC: CustomRule = {\n id: \"VC111\",\n title: \"Lambda Without VPC\",\n severity: \"medium\",\n category: \"Infrastructure\",\n description: \"Lambda functions not placed in a VPC lack network isolation and cannot access VPC-only resources securely.\",\n check(content, filePath) {\n if (!filePath.match(/\\.tf$/)) return [];\n if (!/resource\\s+\"aws_lambda_function\"/.test(content)) return [];\n const matches: RuleMatch[] = [];\n const lambdaPattern = /resource\\s+\"aws_lambda_function\"\\s+\"(\\w+)\"/g;\n let m: RegExpExecArray | null;\n while ((m = lambdaPattern.exec(content)) !== null) {\n if (isCommentLine(content, m.index)) continue;\n const blockEnd = Math.min(m.index + 2000, content.length);\n const blockContent = content.substring(m.index, blockEnd);\n if (!/vpc_config\\s*\\{/.test(blockContent)) {\n const lineNum = content.substring(0, m.index).split(\"\\n\").length;\n matches.push({\n rule: \"VC111\", title: lambdaWithoutVPC.title, severity: \"medium\" as const, category: \"Infrastructure\",\n file: filePath, line: lineNum, snippet: getSnippet(content, lineNum),\n fix: \"Place Lambda functions in a VPC for network isolation.\",\n });\n }\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC112 – Docker Image Using Latest Tag\n// ────────────────────────────────────────────\n\nconst dockerLatestTag: CustomRule = {\n id: \"VC112\",\n title: \"Docker Image Using Latest Tag\",\n severity: \"high\",\n category: \"Configuration\",\n description: \"Using :latest or no tag in Docker FROM directives leads to non-reproducible builds and potential security regressions.\",\n check(content, filePath) {\n if (!filePath.match(/Dockerfile$/i)) return [];\n const matches: RuleMatch[] = [];\n // Match FROM image:latest or FROM image (no tag, no AS, no scratch)\n const fromPattern = /^FROM\\s+(?!scratch)(\\S+?)(?:\\s+AS\\s+\\S+)?\\s*$/gm;\n let m: RegExpExecArray | null;\n while ((m = fromPattern.exec(content)) !== null) {\n const image = m[1];\n // Flag if using :latest or no tag at all (no colon)\n if (image.endsWith(\":latest\") || (!image.includes(\":\") && !image.startsWith(\"$\"))) {\n const lineNum = content.substring(0, m.index).split(\"\\n\").length;\n matches.push({\n rule: \"VC112\", title: dockerLatestTag.title, severity: \"high\" as const, category: \"Configuration\",\n file: filePath, line: lineNum, snippet: getSnippet(content, lineNum),\n fix: \"Pin Docker image versions: FROM node:20-alpine instead of FROM node:latest\",\n });\n }\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC113 – Docker COPY With Sensitive Files\n// ────────────────────────────────────────────\n\nconst dockerCopySensitive: CustomRule = {\n id: \"VC113\",\n title: \"Docker COPY With Sensitive Files\",\n severity: \"high\",\n category: \"Configuration\",\n description: \"Using COPY . . or ADD . . without a .dockerignore can leak .env files, .git history, and other sensitive data into the Docker image.\",\n check(content, filePath) {\n if (!filePath.match(/Dockerfile$/i)) return [];\n // Check for COPY . . or ADD . .\n if (!/(?:COPY|ADD)\\s+\\.\\s+\\./.test(content)) return [];\n return findMatches(content, /(?:COPY|ADD)\\s+\\.\\s+\\./g, dockerCopySensitive, filePath, () =>\n \"Use .dockerignore to exclude .env, .git, node_modules, and sensitive files from the Docker build context.\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC114 – Docker Exposing Too Many Ports\n// ────────────────────────────────────────────\n\nconst dockerTooManyPorts: CustomRule = {\n id: \"VC114\",\n title: \"Docker Exposing Too Many Ports\",\n severity: \"medium\",\n category: \"Configuration\",\n description: \"Exposing many ports or wide port ranges increases the attack surface of a container.\",\n check(content, filePath) {\n if (!filePath.match(/Dockerfile$/i)) return [];\n const matches: RuleMatch[] = [];\n // Detect port ranges like EXPOSE 3000-9000\n const rangePattern = /^EXPOSE\\s+\\d+-\\d+/gm;\n matches.push(...findMatches(content, rangePattern, dockerTooManyPorts, filePath, () =>\n \"Only expose necessary ports. Each EXPOSE should have a clear purpose.\"\n ));\n // Detect multiple EXPOSE directives (more than 3)\n const exposeLines = content.split(\"\\n\").filter(l => /^\\s*EXPOSE\\s+/.test(l));\n if (exposeLines.length > 3) {\n const firstExpose = content.search(/^\\s*EXPOSE\\s+/m);\n if (firstExpose >= 0) {\n const lineNum = content.substring(0, firstExpose).split(\"\\n\").length;\n matches.push({\n rule: \"VC114\", title: dockerTooManyPorts.title, severity: \"medium\" as const, category: \"Configuration\",\n file: filePath, line: lineNum, snippet: getSnippet(content, lineNum),\n fix: \"Only expose necessary ports. Each EXPOSE should have a clear purpose.\",\n });\n }\n }\n return matches;\n },\n};\n\n// ────────────────────────────────────────────\n// VC115 – Kubernetes Secret Not Encrypted\n// ────────────────────────────────────────────\n\nconst k8sSecretNotEncrypted: CustomRule = {\n id: \"VC115\",\n title: \"Kubernetes Secret Not Encrypted\",\n severity: \"high\",\n category: \"Infrastructure\",\n description: \"Kubernetes Secrets stored as plain base64 in manifests are not encrypted and can be trivially decoded. Use sealed-secrets or external-secrets.\",\n check(content, filePath) {\n if (!filePath.match(/\\.(yaml|yml)$/)) return [];\n if (!/kind\\s*:\\s*Secret/i.test(content)) return [];\n // Skip if using sealed-secrets or external-secrets annotations\n if (/sealedsecrets\\.bitnami\\.com|external-secrets\\.io/i.test(content)) return [];\n return findMatches(content, /kind\\s*:\\s*Secret/g, k8sSecretNotEncrypted, filePath, () =>\n \"Use sealed-secrets or external-secrets-operator. Never store plain secrets in manifests.\"\n );\n },\n};\n\n// ────────────────────────────────────────────\n// VC116 – Kubernetes Pod Without Resource Limits\n// ────────────────────────────────────────────\n\nconst k8sNoResourceLimits: CustomRule = {\n id: \"VC116\",\n title: \"Kubernetes Pod Without Resource Limits\",\n severity: \"medium\",\n category: \"Infrastructure\",\n description: \"Pods or deployments without resource limits can consume excessive CPU/memory, causing cluster instability.\",\n check(content, filePath) {\n if (!filePath.match(/\\.(yaml|yml)$/)) return [];\n if (!/kind\\s*:\\s*(?:Pod|Deployment|StatefulSet|DaemonSet|Job|CronJob)/i.test(content)) return [];\n // Check if any container spec has resources.limits\n if (/resources\\s*:\\s*\\n\\s+limits\\s*:/m.test(content)) return [];\n // Also accept inline resources: { limits: ... }\n if (/resources\\s*:.*limits/i.test(content)) return [];\n const kindMatch = content.match(/kind\\s*:\\s*(?:Pod|Deployment|StatefulSet|DaemonSet|Job|CronJob)/i);\n if (!kindMatch) return [];\n const lineNum = content.substring(0, kindMatch.index).split(\"\\n\").length;\n return [{\n rule: \"VC116\", title: k8sNoResourceLimits.title, severity: \"medium\" as const, category: \"Infrastructure\",\n file: filePath, line: lineNum, snippet: getSnippet(content, lineNum),\n fix: \"Set resource limits to prevent pods from consuming excessive CPU/memory.\",\n }];\n },\n};\n\n// ────────────────────────────────────────────\n// RULE TIERS: FREE (30 rules) + PRO (all 116)\n// ────────────────────────────────────────────\n\n// Free tier: core security rules available to everyone\nexport const freeRules: CustomRule[] = [\n hardcodedSecrets, // VC001\n exposedEnvFile, // VC002\n missingAuthMiddleware, // VC003\n supabaseNoRLS, // VC004\n stripeWebhookUnprotected, // VC005\n sqlInjection, // VC006\n xssVulnerability, // VC007\n noRateLimiting, // VC008\n corsWildcard, // VC009\n clientSideAuth, // VC010\n nextPublicSecret, // VC011\n envNotGitignored, // VC014\n evalUsage, // VC015\n unvalidatedRedirect, // VC016\n insecureCookies, // VC017\n exposedAuthSecret, // VC018\n missingCSP, // VC020\n hardcodedJWTSecret, // VC031\n missingHTTPS, // VC032\n exposedDebugMode, // VC033\n insecureRandomness, // VC034\n missingErrorBoundary, // VC036\n exposedStackTraces, // VC037\n missingLockFile, // VC039\n dangerousInnerHTML, // VC063\n consoleLogProduction, // VC097\n emptyCatchBlock, // VC104\n todoLeftInCode, // VC103\n weakHashing, // VC060\n disabledTLSVerification, // VC061\n];\n\n// Pro tier: all rules including advanced detection\nexport const proRules: CustomRule[] = [\n hardcodedSecrets,\n exposedEnvFile,\n missingAuthMiddleware,\n supabaseNoRLS,\n stripeWebhookUnprotected,\n sqlInjection,\n xssVulnerability,\n noRateLimiting,\n corsWildcard,\n clientSideAuth,\n nextPublicSecret,\n firebaseClientConfig,\n supabaseAnonAdmin,\n envNotGitignored,\n evalUsage,\n unvalidatedRedirect,\n insecureCookies,\n exposedAuthSecret,\n insecureElectronWindow,\n missingCSP,\n ipcPathTraversal,\n unsanitizedHTMLExport,\n prototypePollution,\n missingFileSizeLimits,\n unsanitizedFilenames,\n electronNavigationUnrestricted,\n missingSecurityMeta,\n unvalidatedAPIParams,\n unvalidatedEventData,\n insecureDeserialization,\n hardcodedJWTSecret,\n missingHTTPS,\n exposedDebugMode,\n insecureRandomness,\n openRedirectParams,\n missingErrorBoundary,\n exposedStackTraces,\n insecureFileUpload,\n missingLockFile,\n exposedGitDir,\n ssrfVulnerability,\n massAssignment,\n timingAttack,\n logInjection,\n weakPasswordRequirements,\n sessionFixation,\n missingBruteForce,\n nosqlInjection,\n exposedDBCredentials,\n missingDBEncryption,\n graphqlIntrospection,\n missingRequestSizeLimit,\n hardcodedIPAllowlist,\n sensitiveLocalStorage,\n exposedSourceMaps,\n clickjacking,\n overlyPermissiveIAM,\n dockerRunAsRoot,\n exposedDockerPorts,\n weakHashing,\n disabledTLSVerification,\n hardcodedEncryptionKey,\n dangerousInnerHTML,\n exposedServerActions,\n unprotectedAPIRoutes,\n clientComponentSecret,\n insecureDeepLink,\n sensitiveAsyncStorage,\n missingCertPinning,\n androidDebuggable,\n djangoDebug,\n flaskSecretKey,\n pickleDeserialization,\n missingCSRF,\n githubActionsInjection,\n secretsInCI,\n corsServerless,\n k8sPrivileged,\n jwtAlgConfusion,\n regexDos,\n xxeVulnerability,\n ssti,\n javaDeserialization,\n missingSRI,\n exposedAdminRoutes,\n insecureWebSocket,\n missingHSTS,\n sensitiveURLParams,\n missingContentDisposition,\n hostHeaderRedirect,\n raceCondition,\n unsafeObjectAssign,\n unprotectedDownload,\n commandInjection,\n corsLocalhost,\n insecureGRPC,\n consoleLogProduction,\n syncFileOps,\n eventListenerLeak,\n nPlusOneQuery,\n largeBundleImport,\n blockingMainThread,\n todoLeftInCode,\n emptyCatchBlock,\n callbackHell,\n magicNumbers,\n s3BucketNoEncryption,\n securityGroupAllInbound,\n rdsPubliclyAccessible,\n missingCloudTrail,\n lambdaWithoutVPC,\n dockerLatestTag,\n dockerCopySensitive,\n dockerTooManyPorts,\n k8sSecretNotEncrypted,\n k8sNoResourceLimits,\n];\n\n// Default export uses free tier — Pro uses proRules via API\nexport const allRules = freeRules;\n\nexport function runCustomRules(\n content: string,\n filePath: string,\n disabledRules: string[] = [],\n tier: \"free\" | \"pro\" = \"free\",\n): Finding[] {\n const findings: Finding[] = [];\n\n // Skip files that ARE security scanners (avoid scanning ourselves)\n if (/function runScan\\(files\\)|export function runCustomRules/.test(content) && /const (?:rules|allRules)\\s*[:=]/.test(content) && /findMatches/.test(content)) {\n return findings;\n }\n\n const ruleset = tier === \"pro\" ? proRules : freeRules;\n for (const rule of ruleset) {\n if (disabledRules.includes(rule.id)) continue;\n\n const matches = rule.check(content, filePath);\n const compliance = complianceMap[rule.id];\n for (const match of matches) {\n findings.push({\n id: `${match.rule}-${match.file}:${match.line}`,\n rule: match.rule,\n severity: match.severity,\n title: match.title,\n description: rule.description,\n file: match.file,\n line: match.line,\n column: match.column,\n snippet: match.snippet,\n fix: match.fix,\n category: match.category,\n source: \"custom\",\n owasp: compliance?.owasp,\n cwe: compliance?.cwe,\n });\n }\n }\n\n return findings;\n}\n","import { execFile } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { readFile, writeFile, mkdtemp, rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport type { Finding, Severity } from \"../types.js\";\n\ninterface SemgrepSarifResult {\n runs?: Array<{\n results?: Array<{\n ruleId?: string;\n level?: string;\n message?: { text?: string };\n locations?: Array<{\n physicalLocation?: {\n artifactLocation?: { uri?: string };\n region?: {\n startLine?: number;\n startColumn?: number;\n snippet?: { text?: string };\n };\n };\n }>;\n }>;\n }>;\n}\n\nconst SEVERITY_MAP: Record<string, Severity> = {\n error: \"high\",\n warning: \"medium\",\n note: \"low\",\n none: \"info\",\n};\n\nfunction semgrepSeverityToXploitscan(level: string): Severity {\n return SEVERITY_MAP[level] ?? \"medium\";\n}\n\nasync function isSemgrepInstalled(): Promise<boolean> {\n return new Promise((resolve) => {\n execFile(\"semgrep\", [\"--version\"], (error) => {\n resolve(!error);\n });\n });\n}\n\nexport async function runSemgrep(\n directory: string,\n customRulesDir?: string,\n): Promise<{ findings: Finding[]; available: boolean }> {\n const installed = await isSemgrepInstalled();\n if (!installed) {\n return { findings: [], available: false };\n }\n\n const findings: Finding[] = [];\n\n // Create a temp directory for SARIF output\n const tmpDir = await mkdtemp(join(tmpdir(), \"xploitscan-semgrep-\"));\n const sarifPath = join(tmpDir, \"results.sarif\");\n\n try {\n // Build semgrep args\n const args = [\n \"scan\",\n \"--sarif\",\n \"--output\", sarifPath,\n \"--quiet\",\n \"--no-git-ignore\", // We handle .gitignore ourselves\n \"--timeout\", \"30\",\n \"--max-target-bytes\", \"1000000\",\n ];\n\n // Use auto config (community rules) + custom rules if available\n args.push(\"--config\", \"auto\");\n\n if (customRulesDir && existsSync(customRulesDir)) {\n args.push(\"--config\", customRulesDir);\n }\n\n args.push(directory);\n\n // Run semgrep\n await new Promise<void>((resolve, reject) => {\n const proc = execFile(\n \"semgrep\",\n args,\n { timeout: 120_000, maxBuffer: 10 * 1024 * 1024 },\n (error, _stdout, stderr) => {\n // Semgrep returns exit code 1 when findings exist — that's fine\n if (error && error.code !== 1) {\n reject(new Error(`Semgrep failed: ${stderr || error.message}`));\n } else {\n resolve();\n }\n },\n );\n });\n\n // Parse SARIF output\n if (!existsSync(sarifPath)) return { findings, available: true };\n\n const sarifContent = await readFile(sarifPath, \"utf-8\");\n const sarif: SemgrepSarifResult = JSON.parse(sarifContent);\n\n for (const run of sarif.runs ?? []) {\n for (const result of run.results ?? []) {\n const location = result.locations?.[0]?.physicalLocation;\n const filePath = location?.artifactLocation?.uri ?? \"unknown\";\n const line = location?.region?.startLine ?? 1;\n const snippet = location?.region?.snippet?.text ?? \"\";\n\n // Determine category from rule ID\n const ruleId = result.ruleId ?? \"semgrep\";\n const category = categorizeSemgrepRule(ruleId);\n\n findings.push({\n id: `SG-${filePath}:${line}:${ruleId}`,\n rule: ruleId,\n severity: semgrepSeverityToXploitscan(result.level ?? \"warning\"),\n title: truncate(result.message?.text ?? ruleId, 100),\n description: result.message?.text ?? \"\",\n file: filePath.replace(/^file:\\/\\//, \"\"),\n line,\n column: location?.region?.startColumn,\n snippet: formatSnippet(snippet, line),\n category,\n source: \"semgrep\",\n });\n }\n }\n } finally {\n // Clean up temp directory\n await rm(tmpDir, { recursive: true, force: true }).catch(() => {});\n }\n\n return { findings, available: true };\n}\n\nfunction categorizeSemgrepRule(ruleId: string): string {\n const id = ruleId.toLowerCase();\n if (id.includes(\"sql\") || id.includes(\"injection\") || id.includes(\"xss\") || id.includes(\"command\")) return \"Injection\";\n if (id.includes(\"auth\") || id.includes(\"session\")) return \"Authentication\";\n if (id.includes(\"crypto\") || id.includes(\"hash\") || id.includes(\"random\")) return \"Cryptography\";\n if (id.includes(\"cors\") || id.includes(\"header\") || id.includes(\"config\")) return \"Configuration\";\n if (id.includes(\"secret\") || id.includes(\"key\") || id.includes(\"password\") || id.includes(\"credential\")) return \"Secrets\";\n if (id.includes(\"path\") || id.includes(\"traversal\") || id.includes(\"file\")) return \"Path Traversal\";\n if (id.includes(\"deserial\")) return \"Deserialization\";\n return \"Security\";\n}\n\nfunction formatSnippet(text: string, line: number): string {\n if (!text) return \"\";\n const lines = text.split(\"\\n\");\n return lines\n .map((l, i) => {\n const num = line + i;\n return ` ${num.toString().padStart(4)} | ${l}`;\n })\n .join(\"\\n\");\n}\n\nfunction truncate(str: string, max: number): string {\n return str.length > max ? str.substring(0, max - 3) + \"...\" : str;\n}\n","import { execFile } from \"node:child_process\";\nimport { readFile, mkdtemp, rm } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport type { Finding, Severity } from \"../types.js\";\nimport { getSnippet, readFileContents } from \"../utils/files.js\";\n\ninterface GitleaksResult {\n Description: string;\n File: string;\n StartLine: number;\n EndLine: number;\n StartColumn: number;\n EndColumn: number;\n Match: string;\n Secret: string;\n RuleID: string;\n Entropy: number;\n Tags?: string[];\n}\n\nconst RULE_SEVERITY: Record<string, Severity> = {\n \"aws-access-token\": \"critical\",\n \"aws-secret-access-key\": \"critical\",\n \"stripe-access-token\": \"critical\",\n \"github-pat\": \"critical\",\n \"private-key\": \"critical\",\n \"generic-api-key\": \"high\",\n \"slack-webhook\": \"high\",\n \"twilio-api-key\": \"high\",\n \"sendgrid-api-key\": \"high\",\n \"shopify-access-token\": \"high\",\n \"gcp-api-key\": \"critical\",\n \"heroku-api-key\": \"high\",\n \"npm-access-token\": \"critical\",\n \"pypi-upload-token\": \"critical\",\n \"telegram-bot-api-token\": \"high\",\n \"discord-bot-token\": \"high\",\n \"firebase-api-key\": \"high\",\n};\n\nasync function isGitleaksInstalled(): Promise<boolean> {\n return new Promise((resolve) => {\n execFile(\"gitleaks\", [\"version\"], (error) => {\n resolve(!error);\n });\n });\n}\n\nexport async function runGitleaks(\n directory: string,\n): Promise<{ findings: Finding[]; available: boolean }> {\n const installed = await isGitleaksInstalled();\n if (!installed) {\n return { findings: [], available: false };\n }\n\n const findings: Finding[] = [];\n const tmpDir = await mkdtemp(join(tmpdir(), \"xploitscan-gitleaks-\"));\n const reportPath = join(tmpDir, \"results.json\");\n\n try {\n const args = [\n \"detect\",\n \"--source\", directory,\n \"--report-path\", reportPath,\n \"--report-format\", \"json\",\n \"--no-git\",\n \"--exit-code\", \"0\", // Don't fail on findings\n ];\n\n await new Promise<void>((resolve, reject) => {\n execFile(\n \"gitleaks\",\n args,\n { timeout: 60_000, maxBuffer: 10 * 1024 * 1024 },\n (error, _stdout, stderr) => {\n if (error) {\n const sanitizedError = (stderr || error.message).slice(0, 200);\n reject(new Error(`Gitleaks failed: ${sanitizedError}`));\n } else {\n resolve();\n }\n },\n );\n });\n\n // Parse results\n if (!existsSync(reportPath)) return { findings, available: true };\n\n const reportContent = await readFile(reportPath, \"utf-8\");\n if (!reportContent.trim()) return { findings, available: true };\n\n const results: GitleaksResult[] = JSON.parse(reportContent);\n\n for (const result of results) {\n const filePath = result.File;\n const line = result.StartLine + 1; // Gitleaks uses 0-based lines\n const severity = RULE_SEVERITY[result.RuleID] ?? \"high\";\n\n // Read file content for snippet\n const content = readFileContents(directory, filePath);\n const snippet = content ? getSnippet(content, line) : ` ${result.Match}`;\n\n // Redact the actual secret in the description\n const redactedSecret = result.Secret.length > 8\n ? result.Secret.substring(0, 4) + \"...\" + result.Secret.substring(result.Secret.length - 4)\n : \"****\";\n\n findings.push({\n id: `GL-${filePath}:${line}:${result.RuleID}`,\n rule: `GL:${result.RuleID}`,\n severity,\n title: `${result.Description} (detected by Gitleaks)`,\n description: `A secret matching \"${result.RuleID}\" pattern was found: ${redactedSecret}. If this is a real credential, it may already be compromised. Rotate it immediately and move it to environment variables.`,\n file: filePath,\n line,\n column: result.StartColumn,\n snippet,\n fix: `1. Rotate this credential immediately (it may be in git history)\\n2. Move it to a .env file: ${result.RuleID.toUpperCase().replace(/-/g, \"_\")}=<new-value>\\n3. Add .env to .gitignore\\n4. Remove from git history: git filter-branch or BFG Repo Cleaner`,\n category: \"Secrets\",\n source: \"gitleaks\",\n });\n }\n } finally {\n await rm(tmpDir, { recursive: true, force: true }).catch(() => {});\n }\n\n return { findings, available: true };\n}\n","import Anthropic from \"@anthropic-ai/sdk\";\nimport type { Finding, Severity } from \"../types.js\";\n\nconst SYSTEM_PROMPT = `You are a security auditor specializing in code generated by AI tools (Cursor, Lovable, Bolt, Replit, Claude). Your audience is non-expert developers who may not understand security jargon.\n\nAnalyze the provided code for security vulnerabilities. Focus on issues that AI code generators commonly introduce:\n- Missing authentication/authorization\n- Exposed secrets or credentials\n- SQL injection, XSS, and other injection flaws\n- Insecure direct object references (IDOR)\n- Missing input validation\n- Insecure defaults (permissive CORS, no rate limiting)\n- Client-side security checks without server-side enforcement\n- Supabase RLS misconfigurations\n- Unprotected payment/webhook endpoints\n\nFor each vulnerability found, respond with a JSON array of objects:\n{\n \"title\": \"Short, clear title\",\n \"severity\": \"critical|high|medium|low\",\n \"line\": <approximate line number>,\n \"description\": \"Plain-English explanation a non-developer can understand. What's the risk? What could an attacker do?\",\n \"fix\": \"Step-by-step fix instructions with code example if helpful\",\n \"category\": \"Secrets|Authentication|Authorization|Injection|Configuration|Payment Security|Data Exposure\"\n}\n\nIf no vulnerabilities are found, return an empty array: []\n\nRules:\n- Only report real, exploitable issues — no theoretical concerns\n- Be specific about what an attacker could do\n- Explain fixes in beginner-friendly language\n- Reference specific line numbers`;\n\nexport async function analyzeWithAI(\n files: { path: string; content: string }[],\n existingFindings: Finding[],\n): Promise<Finding[]> {\n const apiKey = process.env.ANTHROPIC_API_KEY;\n if (!apiKey) return [];\n\n const client = new Anthropic();\n\n // Build context: send files with existing findings for dedup\n const existingRules = new Set(\n existingFindings.map((f) => `${f.file}:${f.line}:${f.rule}`),\n );\n\n // Batch files into chunks to stay within token limits (~50KB per chunk)\n const chunks = chunkFiles(files, 50_000);\n const allFindings: Finding[] = [];\n\n for (const chunk of chunks) {\n const fileContext = chunk\n .map((f) => `--- ${f.path} ---\\n${f.content}`)\n .join(\"\\n\\n\");\n\n const existingNote = existingFindings.length > 0\n ? `\\n\\nThe following issues have already been found by static rules (do NOT duplicate these):\\n${existingFindings.map((f) => `- ${f.file}:${f.line} — ${f.title}`).join(\"\\n\")}`\n : \"\";\n\n try {\n const response = await client.messages.create({\n model: \"claude-sonnet-4-5-20250514\",\n max_tokens: 4096,\n messages: [\n {\n role: \"user\",\n content: `Analyze these source files for security vulnerabilities:${existingNote}\\n\\n${fileContext}`,\n },\n ],\n system: SYSTEM_PROMPT,\n });\n\n const text = response.content\n .filter((block): block is Anthropic.TextBlock => block.type === \"text\")\n .map((block) => block.text)\n .join(\"\");\n\n // Extract JSON from response (handles markdown code blocks)\n const jsonMatch = text.match(/\\[[\\s\\S]*\\]/);\n if (!jsonMatch) continue;\n\n const parsed = JSON.parse(jsonMatch[0]) as Array<{\n title: string;\n severity: Severity;\n line: number;\n description: string;\n fix: string;\n category: string;\n }>;\n\n for (const item of parsed) {\n // Find which file this finding belongs to\n const matchFile = chunk.find((f) => {\n const lines = f.content.split(\"\\n\");\n return item.line <= lines.length;\n });\n const file = matchFile?.path ?? chunk[0].path;\n\n const key = `${file}:${item.line}:AI`;\n if (existingRules.has(key)) continue;\n\n const content = chunk.find((f) => f.path === file)?.content ?? \"\";\n const lines = content.split(\"\\n\");\n const snippetStart = Math.max(0, item.line - 3);\n const snippetEnd = Math.min(lines.length, item.line + 2);\n const snippet = lines\n .slice(snippetStart, snippetEnd)\n .map((l, i) => {\n const num = snippetStart + i + 1;\n const marker = num === item.line ? \">\" : \" \";\n return `${marker} ${num.toString().padStart(4)} | ${l}`;\n })\n .join(\"\\n\");\n\n allFindings.push({\n id: `AI-${file}:${item.line}`,\n rule: \"AI\",\n severity: item.severity,\n title: item.title,\n description: item.description,\n file,\n line: item.line,\n snippet,\n fix: item.fix,\n category: item.category,\n source: \"ai\",\n });\n }\n } catch (error) {\n // AI analysis failed for this chunk — continue with others\n if (error instanceof Error && error.message.includes(\"API key\")) {\n throw new Error(\n \"Invalid ANTHROPIC_API_KEY. Get one at https://console.anthropic.com/\",\n );\n }\n }\n }\n\n return allFindings;\n}\n\nfunction chunkFiles(\n files: { path: string; content: string }[],\n maxChars: number,\n): { path: string; content: string }[][] {\n const chunks: { path: string; content: string }[][] = [];\n let current: { path: string; content: string }[] = [];\n let currentSize = 0;\n\n for (const file of files) {\n if (currentSize + file.content.length > maxChars && current.length > 0) {\n chunks.push(current);\n current = [];\n currentSize = 0;\n }\n current.push(file);\n currentSize += file.content.length;\n }\n\n if (current.length > 0) chunks.push(current);\n return chunks;\n}\n","/**\n * AST-based JavaScript/TypeScript analyzer\n * Uses regex-based pseudo-AST parsing (no external deps) to understand code structure\n * and reduce false positives from comments, strings, and non-executable code.\n */\n\nimport type { Finding, Severity } from \"../types.js\";\n\n// ────────────────────────────────────────────\n// Code Structure Detection\n// ────────────────────────────────────────────\n\ninterface CodeContext {\n isComment: boolean;\n isString: boolean;\n isImport: boolean;\n isTestFile: boolean;\n isTypeDefinition: boolean;\n functionScope: string | null;\n nearestAssignment: string | null;\n}\n\n/** Strip all comments from JS/TS/Python code to prevent false positives */\nexport function stripComments(content: string): string {\n let result = \"\";\n let i = 0;\n let inSingleQuote = false;\n let inDoubleQuote = false;\n let inTemplate = false;\n let inSingleLineComment = false;\n let inMultiLineComment = false;\n\n while (i < content.length) {\n const ch = content[i];\n const next = content[i + 1];\n\n if (inSingleLineComment) {\n if (ch === \"\\n\") {\n inSingleLineComment = false;\n result += ch;\n }\n i++;\n continue;\n }\n\n if (inMultiLineComment) {\n if (ch === \"*\" && next === \"/\") {\n inMultiLineComment = false;\n i += 2;\n } else {\n if (ch === \"\\n\") result += ch; // preserve line numbers\n i++;\n }\n continue;\n }\n\n if (inSingleQuote) {\n result += ch;\n if (ch === \"'\" && content[i - 1] !== \"\\\\\") inSingleQuote = false;\n i++;\n continue;\n }\n\n if (inDoubleQuote) {\n result += ch;\n if (ch === '\"' && content[i - 1] !== \"\\\\\") inDoubleQuote = false;\n i++;\n continue;\n }\n\n if (inTemplate) {\n result += ch;\n if (ch === \"`\" && content[i - 1] !== \"\\\\\") inTemplate = false;\n i++;\n continue;\n }\n\n // Check for comment starts\n if (ch === \"/\" && next === \"/\") {\n inSingleLineComment = true;\n i += 2;\n continue;\n }\n if (ch === \"/\" && next === \"*\") {\n inMultiLineComment = true;\n i += 2;\n continue;\n }\n // Python/YAML comments\n if (ch === \"#\" && !inSingleQuote && !inDoubleQuote) {\n inSingleLineComment = true;\n i++;\n continue;\n }\n\n // Check for string starts\n if (ch === \"'\") inSingleQuote = true;\n if (ch === '\"') inDoubleQuote = true;\n if (ch === \"`\") inTemplate = true;\n\n result += ch;\n i++;\n }\n\n return result;\n}\n\n/** Detect if a line index falls within a function body */\nexport function getFunctionScope(content: string, lineIndex: number): string | null {\n const lines = content.split(\"\\n\");\n // Walk backwards from the match line to find enclosing function\n for (let i = lineIndex; i >= 0; i--) {\n const line = lines[i];\n const funcMatch = line.match(/(?:function\\s+(\\w+)|(?:const|let|var)\\s+(\\w+)\\s*=\\s*(?:async\\s+)?(?:function|\\([^)]*\\)\\s*=>)|(\\w+)\\s*\\([^)]*\\)\\s*\\{)/);\n if (funcMatch) {\n return funcMatch[1] || funcMatch[2] || funcMatch[3] || \"anonymous\";\n }\n }\n return null;\n}\n\n/** Check if content between two positions has a validation/sanitization pattern */\nexport function hasValidationBetween(content: string, startLine: number, endLine: number): boolean {\n const lines = content.split(\"\\n\");\n const segment = lines.slice(startLine, endLine + 1).join(\"\\n\");\n return /(?:validate|sanitize|escape|check|verify|assert|ensure|guard|protect|filter|whitelist|allowlist|isValid|isAllowed|isSafe)/i.test(segment);\n}\n\n/** Detect data flow: does user input reach a dangerous sink? */\nexport function tracesUserInput(content: string, sinkLine: number, linesBack: number = 15): boolean {\n const lines = content.split(\"\\n\");\n const start = Math.max(0, sinkLine - linesBack);\n const segment = lines.slice(start, sinkLine + 1).join(\"\\n\");\n\n const userInputSources = /(?:req\\.(?:body|query|params|headers)|body\\.|input\\.|params\\.|args\\.|request\\.|formData|searchParams|useSearchParams|URLSearchParams)/i;\n return userInputSources.test(segment);\n}\n\n/** Extract all import/require statements to understand dependencies */\nexport function extractImports(content: string): string[] {\n const imports: string[] = [];\n const patterns = [\n /import\\s+.*?from\\s+[\"'`]([^\"'`]+)[\"'`]/g,\n /require\\s*\\(\\s*[\"'`]([^\"'`]+)[\"'`]\\s*\\)/g,\n ];\n for (const p of patterns) {\n let m;\n while ((m = p.exec(content)) !== null) {\n imports.push(m[1]);\n }\n }\n return imports;\n}\n\n/** Check if a file imports/uses a specific security middleware */\nexport function hasSecurityMiddleware(content: string): { auth: boolean; rateLimit: boolean; helmet: boolean; cors: boolean; csrf: boolean } {\n return {\n auth: /(?:requireAuth|isAuthenticated|authenticate|passport|jwt\\.verify|clerk|auth0|nextauth|session\\.user|getServerSession|getAuth|withAuth|authMiddleware)/i.test(content),\n rateLimit: /(?:rateLimit|rate-limit|express-rate-limit|throttle|slowDown|limiter)/i.test(content),\n helmet: /(?:helmet|security-headers|securityHeaders)/i.test(content),\n cors: /(?:cors\\(|corsMiddleware|allowedOrigins)/i.test(content),\n csrf: /(?:csrf|csurf|csrfToken|_csrf)/i.test(content),\n };\n}\n\n// ────────────────────────────────────────────\n// AST-Enhanced Rule Runner\n// ────────────────────────────────────────────\n\nexport interface ASTContext {\n strippedContent: string; // Code with comments removed\n imports: string[]; // All imports/requires\n middleware: ReturnType<typeof hasSecurityMiddleware>;\n isTestFile: boolean;\n isConfigFile: boolean;\n isScannerFile: boolean; // Self-detection: is this a security scanner?\n}\n\nexport function buildASTContext(content: string, filePath: string): ASTContext {\n return {\n strippedContent: stripComments(content),\n imports: extractImports(content),\n middleware: hasSecurityMiddleware(content),\n isTestFile: /(?:\\.test\\.|\\.spec\\.|__tests__|__mocks__|\\.stories\\.|fixtures?\\/|mocks?\\/|\\.cy\\.|\\.e2e\\.)/i.test(filePath),\n isConfigFile: /(?:\\.config\\.|config\\/|\\.rc$|tsconfig|next\\.config|vite\\.config|webpack\\.config)/i.test(filePath),\n isScannerFile: /(?:custom-rules|scanner|security-check|eslint-plugin|lint)/i.test(filePath) &&\n /(?:findMatches|check\\s*\\(content|rule\\.check|severity|category)/i.test(content),\n };\n}\n","/**\n * Dependency Vulnerability Scanner\n * Parses package.json, requirements.txt, Gemfile, etc. and checks\n * for known vulnerable packages and risky dependency patterns.\n */\n\nimport type { Finding } from \"../types.js\";\n\n// Known vulnerable packages and their details\n// Format: package -> { minSafeVersion, cve, severity, description }\ninterface VulnEntry {\n minSafe: string;\n cve: string;\n severity: \"critical\" | \"high\" | \"medium\" | \"low\";\n title: string;\n description: string;\n fix: string;\n}\n\n// Well-known vulnerable npm packages (manually curated, high-signal)\nconst KNOWN_VULN_NPM: Record<string, VulnEntry[]> = {\n \"lodash\": [{\n minSafe: \"4.17.21\", cve: \"CVE-2021-23337\", severity: \"critical\",\n title: \"Lodash Prototype Pollution\",\n description: \"lodash before 4.17.21 is vulnerable to prototype pollution via set, setWith, and zipObjectDeep.\",\n fix: \"Upgrade lodash to >= 4.17.21: npm install lodash@latest\"\n }],\n \"axios\": [{\n minSafe: \"1.6.0\", cve: \"CVE-2023-45857\", severity: \"high\",\n title: \"Axios CSRF Vulnerability\",\n description: \"axios before 1.6.0 inadvertently leaks XSRF-TOKEN cookie in cross-site requests.\",\n fix: \"Upgrade axios to >= 1.6.0: npm install axios@latest\"\n }],\n \"express\": [{\n minSafe: \"4.19.2\", cve: \"CVE-2024-29041\", severity: \"medium\",\n title: \"Express Open Redirect\",\n description: \"Express before 4.19.2 is vulnerable to open redirect via crafted URLs.\",\n fix: \"Upgrade express to >= 4.19.2: npm install express@latest\"\n }],\n \"jsonwebtoken\": [{\n minSafe: \"9.0.0\", cve: \"CVE-2022-23529\", severity: \"high\",\n title: \"jsonwebtoken Insecure Key Handling\",\n description: \"jsonwebtoken before 9.0.0 allows attackers to set secretOrPublicKey to a malicious object.\",\n fix: \"Upgrade jsonwebtoken to >= 9.0.0: npm install jsonwebtoken@latest\"\n }],\n \"node-fetch\": [{\n minSafe: \"2.6.7\", cve: \"CVE-2022-0235\", severity: \"high\",\n title: \"node-fetch Header Exposure\",\n description: \"node-fetch before 2.6.7 exposes authorization headers on redirect to different origin.\",\n fix: \"Upgrade node-fetch to >= 2.6.7 or switch to native fetch (Node 18+).\"\n }],\n \"minimatch\": [{\n minSafe: \"3.0.5\", cve: \"CVE-2022-3517\", severity: \"high\",\n title: \"Minimatch ReDoS\",\n description: \"minimatch before 3.0.5 is vulnerable to Regular Expression Denial of Service.\",\n fix: \"Upgrade minimatch to >= 3.0.5: npm install minimatch@latest\"\n }],\n \"moment\": [{\n minSafe: \"999.0.0\", cve: \"N/A\", severity: \"medium\",\n title: \"Moment.js is Deprecated\",\n description: \"moment.js is in maintenance mode with known path traversal issues. Consider alternatives.\",\n fix: \"Migrate to date-fns, dayjs, or Temporal API. See: https://momentjs.com/docs/#/-project-status/\"\n }],\n \"request\": [{\n minSafe: \"999.0.0\", cve: \"N/A\", severity: \"medium\",\n title: \"Request Package Deprecated\",\n description: \"The 'request' package is deprecated and no longer receives security updates.\",\n fix: \"Migrate to node-fetch, axios, got, or native fetch (Node 18+).\"\n }],\n \"underscore\": [{\n minSafe: \"1.13.6\", cve: \"CVE-2021-23358\", severity: \"high\",\n title: \"Underscore.js Arbitrary Code Execution\",\n description: \"underscore before 1.13.6 allows arbitrary code execution via the template function.\",\n fix: \"Upgrade underscore to >= 1.13.6 or migrate to lodash.\"\n }],\n \"tar\": [{\n minSafe: \"6.2.1\", cve: \"CVE-2024-28863\", severity: \"high\",\n title: \"Tar Path Traversal\",\n description: \"tar before 6.2.1 is vulnerable to denial of service via crafted archives.\",\n fix: \"Upgrade tar to >= 6.2.1: npm install tar@latest\"\n }],\n \"semver\": [{\n minSafe: \"7.5.2\", cve: \"CVE-2022-25883\", severity: \"medium\",\n title: \"Semver ReDoS\",\n description: \"semver before 7.5.2 is vulnerable to Regular Expression Denial of Service.\",\n fix: \"Upgrade semver to >= 7.5.2: npm install semver@latest\"\n }],\n \"xml2js\": [{\n minSafe: \"0.5.0\", cve: \"CVE-2023-0842\", severity: \"medium\",\n title: \"xml2js Prototype Pollution\",\n description: \"xml2js before 0.5.0 is vulnerable to prototype pollution when parsing XML.\",\n fix: \"Upgrade xml2js to >= 0.5.0: npm install xml2js@latest\"\n }],\n};\n\n// Known vulnerable Python packages\nconst KNOWN_VULN_PYTHON: Record<string, VulnEntry[]> = {\n \"django\": [{\n minSafe: \"4.2.11\", cve: \"CVE-2024-27351\", severity: \"high\",\n title: \"Django ReDoS in Truncator\",\n description: \"Django before 4.2.11 is vulnerable to Regular Expression Denial of Service.\",\n fix: \"Upgrade Django to >= 4.2.11: pip install Django --upgrade\"\n }],\n \"flask\": [{\n minSafe: \"2.3.2\", cve: \"CVE-2023-30861\", severity: \"high\",\n title: \"Flask Session Cookie Vulnerability\",\n description: \"Flask before 2.3.2 may set permanent session cookies on redirect responses.\",\n fix: \"Upgrade Flask to >= 2.3.2: pip install Flask --upgrade\"\n }],\n \"pillow\": [{\n minSafe: \"10.2.0\", cve: \"CVE-2023-50447\", severity: \"critical\",\n title: \"Pillow Arbitrary Code Execution\",\n description: \"Pillow before 10.2.0 is vulnerable to arbitrary code execution via crafted images.\",\n fix: \"Upgrade Pillow to >= 10.2.0: pip install Pillow --upgrade\"\n }],\n \"requests\": [{\n minSafe: \"2.31.0\", cve: \"CVE-2023-32681\", severity: \"medium\",\n title: \"Requests Proxy Header Leak\",\n description: \"requests before 2.31.0 leaks Proxy-Authorization headers to destination servers.\",\n fix: \"Upgrade requests to >= 2.31.0: pip install requests --upgrade\"\n }],\n \"pyyaml\": [{\n minSafe: \"6.0.1\", cve: \"CVE-2022-41316\", severity: \"high\",\n title: \"PyYAML Unsafe Loading\",\n description: \"PyYAML has known deserialization vulnerabilities. Always use yaml.safe_load().\",\n fix: \"Upgrade PyYAML to >= 6.0.1 and use yaml.safe_load() instead of yaml.load().\"\n }],\n \"jinja2\": [{\n minSafe: \"3.1.3\", cve: \"CVE-2024-22195\", severity: \"medium\",\n title: \"Jinja2 XSS Vulnerability\",\n description: \"Jinja2 before 3.1.3 is vulnerable to XSS via xmlattr filter.\",\n fix: \"Upgrade Jinja2 to >= 3.1.3: pip install Jinja2 --upgrade\"\n }],\n};\n\n// Risky patterns in dependency configs\ninterface DepPattern {\n id: string;\n title: string;\n severity: \"critical\" | \"high\" | \"medium\" | \"low\";\n description: string;\n fix: string;\n test: (content: string, filePath: string) => boolean;\n}\n\nconst DEP_PATTERNS: DepPattern[] = [\n {\n id: \"DEP001\", title: \"Wildcard Dependency Version\", severity: \"high\",\n description: \"Using '*' or 'latest' as a dependency version allows any version to be installed, including malicious ones.\",\n fix: \"Pin dependency versions: use exact (1.2.3) or caret (^1.2.3) versions, never '*' or 'latest'.\",\n test: (content, filePath) => filePath.endsWith(\"package.json\") && /[\"']\\*[\"']|[\"']latest[\"']/.test(content),\n },\n {\n id: \"DEP002\", title: \"Git Dependency Without Commit Hash\", severity: \"medium\",\n description: \"Git dependencies without a pinned commit hash can be replaced with malicious code.\",\n fix: \"Pin git dependencies to a specific commit: git+https://github.com/user/repo#commit-hash\",\n test: (content, filePath) => filePath.endsWith(\"package.json\") && /git\\+https?:\\/\\/[^#\"]+[\"']/.test(content),\n },\n {\n id: \"DEP003\", title: \"Postinstall Script in Package\", severity: \"medium\",\n description: \"postinstall scripts run automatically after npm install and can execute arbitrary code.\",\n fix: \"Audit postinstall scripts carefully. Use --ignore-scripts flag for untrusted packages.\",\n test: (content, filePath) => filePath.endsWith(\"package.json\") && /\"postinstall\"\\s*:/.test(content),\n },\n {\n id: \"DEP004\", title: \"No Package Lock File\", severity: \"medium\",\n description: \"Without a lockfile, npm install may resolve different versions on different machines.\",\n fix: \"Commit your lockfile (package-lock.json, pnpm-lock.yaml, or yarn.lock).\",\n test: (content, filePath) => filePath.endsWith(\".gitignore\") && /package-lock\\.json|pnpm-lock\\.yaml|yarn\\.lock/.test(content),\n },\n {\n id: \"DEP005\", title: \"HTTP Registry URL\", severity: \"high\",\n description: \"Using HTTP (not HTTPS) for npm registry allows man-in-the-middle attacks on package downloads.\",\n fix: \"Use HTTPS for registry: registry=https://registry.npmjs.org/\",\n test: (content, filePath) => filePath.endsWith(\".npmrc\") && /registry\\s*=\\s*http:\\/\\//.test(content),\n },\n];\n\nfunction compareVersions(v1: string, v2: string): number {\n const parts1 = v1.replace(/^[^0-9]*/, \"\").split(\".\").map(Number);\n const parts2 = v2.replace(/^[^0-9]*/, \"\").split(\".\").map(Number);\n for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {\n const a = parts1[i] || 0;\n const b = parts2[i] || 0;\n if (a < b) return -1;\n if (a > b) return 1;\n }\n return 0;\n}\n\nfunction getSnippet(content: string, line: number): string {\n const lines = content.split(\"\\n\");\n const start = Math.max(0, line - 2);\n const end = Math.min(lines.length, line + 2);\n return lines.slice(start, end).map((l, i) => {\n const lineNum = start + i + 1;\n const prefix = lineNum === line ? \">\" : \" \";\n return `${prefix} ${String(lineNum).padStart(5)} | ${l}`;\n }).join(\"\\n\");\n}\n\nexport function scanDependencies(files: { path: string; content: string }[]): Finding[] {\n const findings: Finding[] = [];\n\n for (const { path: filePath, content } of files) {\n // npm package.json\n if (filePath.endsWith(\"package.json\") && !filePath.includes(\"node_modules\")) {\n try {\n const pkg = JSON.parse(content);\n const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };\n\n for (const [name, version] of Object.entries(allDeps)) {\n const vulns = KNOWN_VULN_NPM[name];\n if (!vulns) continue;\n\n const versionStr = String(version).replace(/^[\\^~>=<]*/g, \"\");\n for (const vuln of vulns) {\n if (compareVersions(versionStr, vuln.minSafe) < 0) {\n const line = content.split(\"\\n\").findIndex(l => l.includes(`\"${name}\"`)) + 1;\n findings.push({\n id: `${vuln.cve}-${filePath}:${line}`,\n rule: vuln.cve,\n severity: vuln.severity,\n title: vuln.title,\n description: vuln.description,\n file: filePath,\n line,\n snippet: getSnippet(content, line),\n fix: vuln.fix,\n category: \"Dependencies\",\n source: \"custom\",\n owasp: \"A06:2021\",\n cwe: \"CWE-1395\",\n });\n }\n }\n }\n } catch {\n // Invalid JSON — skip\n }\n }\n\n // Python requirements.txt\n if (filePath.match(/requirements.*\\.txt$/i)) {\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n const match = line.match(/^([a-zA-Z0-9_-]+)(?:[=<>!~]+(.+))?/);\n if (!match) continue;\n\n const name = match[1].toLowerCase();\n const version = match[2] || \"0.0.0\";\n const vulns = KNOWN_VULN_PYTHON[name];\n if (!vulns) continue;\n\n for (const vuln of vulns) {\n if (compareVersions(version, vuln.minSafe) < 0) {\n findings.push({\n id: `${vuln.cve}-${filePath}:${i + 1}`,\n rule: vuln.cve,\n severity: vuln.severity,\n title: vuln.title,\n description: vuln.description,\n file: filePath,\n line: i + 1,\n snippet: getSnippet(content, i + 1),\n fix: vuln.fix,\n category: \"Dependencies\",\n source: \"custom\",\n owasp: \"A06:2021\",\n cwe: \"CWE-1395\",\n });\n }\n }\n }\n }\n\n // Dependency pattern checks\n for (const pattern of DEP_PATTERNS) {\n if (pattern.test(content, filePath)) {\n findings.push({\n id: `${pattern.id}-${filePath}:1`,\n rule: pattern.id,\n severity: pattern.severity,\n title: pattern.title,\n description: pattern.description,\n file: filePath,\n line: 1,\n snippet: getSnippet(content, 1),\n fix: pattern.fix,\n category: \"Dependencies\",\n source: \"custom\",\n owasp: \"A06:2021\",\n cwe: \"CWE-1395\",\n });\n }\n }\n }\n\n return findings;\n}\n","/**\n * Secret Entropy Detection Scanner\n * Detects high-entropy strings that are likely secrets/keys/tokens\n * regardless of their naming pattern. Uses Shannon entropy calculation.\n */\n\nimport type { Finding } from \"../types.js\";\n\n// ────────────────────────────────────────────\n// Shannon Entropy Calculation\n// ────────────────────────────────────────────\n\nfunction shannonEntropy(str: string): number {\n const freq: Record<string, number> = {};\n for (const ch of str) {\n freq[ch] = (freq[ch] || 0) + 1;\n }\n const len = str.length;\n let entropy = 0;\n for (const count of Object.values(freq)) {\n const p = count / len;\n entropy -= p * Math.log2(p);\n }\n return entropy;\n}\n\n// ────────────────────────────────────────────\n// Known Safe Patterns (allowlist)\n// ────────────────────────────────────────────\n\nconst SAFE_PATTERNS = [\n // UUIDs\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,\n // Git commit hashes\n /^[0-9a-f]{40}$/i,\n // Short git hashes\n /^[0-9a-f]{7,8}$/i,\n // Hex colors\n /^#?[0-9a-fA-F]{3,8}$/,\n // Base64 encoded small data (< 20 chars)\n /^[A-Za-z0-9+/]{1,19}={0,2}$/,\n // Package versions\n /^\\d+\\.\\d+\\.\\d+/,\n // File hashes (integrity)\n /^sha\\d+-/i,\n // URLs without credentials\n /^https?:\\/\\/[^:@]*$/,\n // Date/time strings\n /^\\d{4}-\\d{2}-\\d{2}/,\n // Locale strings\n /^[a-z]{2}-[A-Z]{2}$/,\n // Common encodings\n /^utf-?8|ascii|latin|iso-8859/i,\n // MIME types\n /^(?:application|text|image|audio|video)\\//,\n // CSS/HTML values\n /^(?:inherit|none|auto|block|flex|grid|absolute|relative|fixed|px|em|rem|%)/,\n // Common placeholder/test values\n /^(?:test|example|sample|demo|placeholder|temp|tmp|foo|bar|baz|lorem|ipsum)/i,\n // DOCTYPE/DTD URLs\n /DTD|DOCTYPE|w3\\.org|apple\\.com\\/DTDs/i,\n // XML namespaces\n /xmlns|schema|xsd|xsi/i,\n // npm/package registry URLs\n /^https?:\\/\\/registry\\.npmjs\\.org\\//,\n /^https?:\\/\\/registry\\.yarnpkg\\.com\\//,\n // Package integrity hashes (sha512-..., sha256-...)\n /^sha\\d+-[A-Za-z0-9+/=]+$/,\n // Resolved package URLs (.tgz)\n /\\.tgz$/,\n // npm resolved URLs (any registry URL with package tarball)\n /registry.*\\/-\\/.*\\.tgz$/,\n];\n\n// File types that shouldn't be scanned for entropy\nconst SKIP_FILES = /\\.(css|scss|less|svg|md|txt|html?|xml|yml|yaml|toml|lock|map|woff2?|ttf|eot|ico|png|jpg|gif|webp)$/i;\n\n// File names that should be completely excluded from entropy scanning\nconst SKIP_FILENAMES = /(?:package-lock\\.json|pnpm-lock\\.yaml|yarn\\.lock|composer\\.lock|Gemfile\\.lock|Cargo\\.lock|poetry\\.lock|Pipfile\\.lock|shrinkwrap\\.json)$/i;\n\n// Variable names that commonly hold non-secret long strings\nconst SAFE_VAR_NAMES = /(?:description|message|text|label|title|content|template|html|svg|css|style|class|query|mutation|schema|regex|pattern|format|placeholder|comment|url|path|route|endpoint|href|src|alt|name|type|version|encoding|charset)/i;\n\n// ────────────────────────────────────────────\n// Scanner\n// ────────────────────────────────────────────\n\ninterface EntropyMatch {\n value: string;\n line: number;\n entropy: number;\n context: string;\n}\n\nfunction getSnippet(content: string, line: number): string {\n const lines = content.split(\"\\n\");\n const start = Math.max(0, line - 2);\n const end = Math.min(lines.length, line + 2);\n return lines.slice(start, end).map((l, i) => {\n const lineNum = start + i + 1;\n const prefix = lineNum === line ? \">\" : \" \";\n return `${prefix} ${String(lineNum).padStart(5)} | ${l}`;\n }).join(\"\\n\");\n}\n\nexport function scanEntropy(files: { path: string; content: string }[]): Finding[] {\n const findings: Finding[] = [];\n\n for (const { path: filePath, content } of files) {\n // Skip non-source files\n if (SKIP_FILES.test(filePath)) continue;\n if (SKIP_FILENAMES.test(filePath)) continue;\n if (filePath.includes(\"node_modules\")) continue;\n if (filePath.includes(\".min.\")) continue;\n if (/(?:\\.test\\.|\\.spec\\.|__tests__|__mocks__|fixtures?\\/)/i.test(filePath)) continue;\n\n const lines = content.split(\"\\n\");\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n\n // Skip comment lines\n const trimmed = line.trimStart();\n if (trimmed.startsWith(\"//\") || trimmed.startsWith(\"#\") || trimmed.startsWith(\"*\") || trimmed.startsWith(\"/*\")) continue;\n\n // Find string assignments (quotes or backticks)\n const stringPattern = /(?:[:=]\\s*)([\"'`])([^\"'`\\n]{20,120})\\1/g;\n let match;\n\n while ((match = stringPattern.exec(line)) !== null) {\n const value = match[2];\n\n // Skip known safe patterns\n if (SAFE_PATTERNS.some(p => p.test(value))) continue;\n\n // Skip if the variable name suggests non-secret content\n const beforeAssign = line.substring(0, match.index);\n if (SAFE_VAR_NAMES.test(beforeAssign)) continue;\n\n // Skip if it looks like a URL without credentials\n if (/^https?:\\/\\/[^:@]*$/.test(value)) continue;\n\n // Skip if it contains spaces (likely a sentence/message)\n if ((value.match(/\\s/g) || []).length > 2) continue;\n\n // Calculate entropy\n const entropy = shannonEntropy(value);\n\n // High entropy thresholds:\n // - Hex strings (charset 16): entropy > 3.0\n // - Base64 strings (charset 64): entropy > 4.5\n // - General strings: entropy > 4.0\n const isHex = /^[0-9a-fA-F]+$/.test(value);\n const isBase64 = /^[A-Za-z0-9+/]+=*$/.test(value);\n\n let threshold = 4.0;\n if (isHex) threshold = 3.0;\n else if (isBase64) threshold = 4.5;\n\n // Minimum length for detection\n if (value.length < 20) continue;\n\n if (entropy >= threshold) {\n // Additional context checks to reduce false positives\n const varName = beforeAssign.match(/(\\w+)\\s*[:=]\\s*$/)?.[1] || \"\";\n\n // Boost confidence if variable name suggests secret\n const isLikelySecret = /(?:key|secret|token|password|passwd|pwd|api_?key|auth|credential|private|signing)/i.test(varName);\n\n // Only report if entropy is very high OR variable name suggests secret\n if (entropy >= 4.5 || isLikelySecret) {\n // Mask the value for display\n const masked = value.substring(0, 6) + \"...\" + value.substring(value.length - 4);\n\n findings.push({\n id: `ENTROPY-${filePath}:${i + 1}`,\n rule: \"ENTROPY\",\n severity: isLikelySecret ? \"critical\" : \"high\",\n title: \"High-Entropy String Detected (Possible Secret)\",\n description: `Found a high-entropy string (${entropy.toFixed(1)} bits) that may be a hardcoded secret or API key: \"${masked}\"`,\n file: filePath,\n line: i + 1,\n snippet: getSnippet(content, i + 1),\n fix: \"If this is a secret, move it to an environment variable. If it's not a secret (e.g., hash, encoded data), add it to .xploitscanignore.\",\n category: \"Secrets\",\n source: \"custom\",\n owasp: \"A02:2021\",\n cwe: \"CWE-798\",\n });\n }\n }\n }\n }\n }\n\n return findings;\n}\n","/**\n * Configuration File Deep Analyzer\n * Analyzes tsconfig, next.config, Dockerfile, GitHub Actions,\n * and other config files for security misconfigurations.\n */\n\nimport type { Finding } from \"../types.js\";\n\nfunction getSnippet(content: string, line: number): string {\n const lines = content.split(\"\\n\");\n const start = Math.max(0, line - 2);\n const end = Math.min(lines.length, line + 2);\n return lines.slice(start, end).map((l, i) => {\n const lineNum = start + i + 1;\n const prefix = lineNum === line ? \">\" : \" \";\n return `${prefix} ${String(lineNum).padStart(5)} | ${l}`;\n }).join(\"\\n\");\n}\n\ninterface ConfigCheck {\n id: string;\n title: string;\n severity: \"critical\" | \"high\" | \"medium\" | \"low\";\n category: string;\n description: string;\n fix: string;\n owasp: string;\n cwe: string;\n filePattern: RegExp;\n check: (content: string, filePath: string) => { line: number; snippet: string } | null;\n}\n\nconst CONFIG_CHECKS: ConfigCheck[] = [\n // ── TypeScript Config ──\n {\n id: \"CFG001\", title: \"TypeScript Strict Mode Disabled\", severity: \"medium\",\n category: \"Configuration\", description: \"TypeScript without strict mode misses type errors that can cause runtime bugs and security issues.\",\n fix: 'Enable strict mode in tsconfig.json: \"strict\": true',\n owasp: \"A05:2021\", cwe: \"CWE-710\",\n filePattern: /tsconfig\\.json$/,\n check(content) {\n try {\n if (/\"strict\"\\s*:\\s*false/.test(content)) {\n const line = content.split(\"\\n\").findIndex(l => /strict/.test(l)) + 1;\n return { line, snippet: getSnippet(content, line) };\n }\n if (!/\"strict\"\\s*:\\s*true/.test(content) && /\"compilerOptions\"/.test(content)) {\n return { line: 1, snippet: getSnippet(content, 1) };\n }\n } catch {}\n return null;\n },\n },\n {\n id: \"CFG002\", title: \"TypeScript allowJs Without checkJs\", severity: \"low\",\n category: \"Configuration\", description: \"allowJs without checkJs means JavaScript files bypass type checking entirely.\",\n fix: 'Add \"checkJs\": true alongside \"allowJs\": true in tsconfig.json.',\n owasp: \"A05:2021\", cwe: \"CWE-710\",\n filePattern: /tsconfig\\.json$/,\n check(content) {\n if (/\"allowJs\"\\s*:\\s*true/.test(content) && !/\"checkJs\"\\s*:\\s*true/.test(content)) {\n const line = content.split(\"\\n\").findIndex(l => /allowJs/.test(l)) + 1;\n return { line, snippet: getSnippet(content, line) };\n }\n return null;\n },\n },\n\n // ── Next.js Config ──\n {\n id: \"CFG003\", title: \"Next.js Missing Security Headers\", severity: \"medium\",\n category: \"Configuration\", description: \"Next.js app without security headers in next.config is missing important protections.\",\n fix: \"Add a headers() function to next.config.js with X-Frame-Options, X-Content-Type-Options, Referrer-Policy, and Content-Security-Policy.\",\n owasp: \"A05:2021\", cwe: \"CWE-693\",\n filePattern: /next\\.config\\.(js|mjs|ts)$/,\n check(content) {\n if (!/headers\\s*\\(/.test(content) && !/securityHeaders|security-headers/.test(content)) {\n return { line: 1, snippet: getSnippet(content, 1) };\n }\n return null;\n },\n },\n {\n id: \"CFG004\", title: \"Next.js Powered-By Header Not Disabled\", severity: \"low\",\n category: \"Configuration\", description: \"Next.js exposes X-Powered-By header by default, revealing your tech stack.\",\n fix: 'Add poweredByHeader: false to next.config.js.',\n owasp: \"A05:2021\", cwe: \"CWE-200\",\n filePattern: /next\\.config\\.(js|mjs|ts)$/,\n check(content) {\n if (!/poweredByHeader\\s*:\\s*false/.test(content)) {\n return { line: 1, snippet: getSnippet(content, 1) };\n }\n return null;\n },\n },\n\n // ── Dockerfile ──\n {\n id: \"CFG005\", title: \"Dockerfile Using Latest Tag\", severity: \"medium\",\n category: \"Configuration\", description: \"Using :latest tag in FROM makes builds non-reproducible and may pull vulnerable images.\",\n fix: \"Pin to a specific version: FROM node:20-alpine instead of FROM node:latest.\",\n owasp: \"A06:2021\", cwe: \"CWE-1395\",\n filePattern: /Dockerfile$/i,\n check(content) {\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n if (/^FROM\\s+\\S+:latest/i.test(lines[i].trim()) || /^FROM\\s+\\w+\\s*$/i.test(lines[i].trim())) {\n return { line: i + 1, snippet: getSnippet(content, i + 1) };\n }\n }\n return null;\n },\n },\n {\n id: \"CFG006\", title: \"Dockerfile Not Using Multi-Stage Build\", severity: \"low\",\n category: \"Configuration\", description: \"Single-stage Docker builds include build tools in the final image, increasing attack surface.\",\n fix: \"Use multi-stage builds: first stage for building, second stage (FROM alpine) for running.\",\n owasp: \"A05:2021\", cwe: \"CWE-1059\",\n filePattern: /Dockerfile$/i,\n check(content) {\n const fromCount = (content.match(/^FROM\\s/gmi) || []).length;\n if (fromCount <= 1 && content.includes(\"npm\") && content.length > 200) {\n return { line: 1, snippet: getSnippet(content, 1) };\n }\n return null;\n },\n },\n {\n id: \"CFG007\", title: \"Dockerfile Copies .env File\", severity: \"critical\",\n category: \"Configuration\", description: \"COPY that includes .env files bakes secrets into the Docker image layer.\",\n fix: \"Add .env to .dockerignore. Use build args or runtime env vars instead.\",\n owasp: \"A02:2021\", cwe: \"CWE-312\",\n filePattern: /Dockerfile$/i,\n check(content) {\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n if (/^COPY\\s.*\\.env\\b/i.test(lines[i].trim())) {\n return { line: i + 1, snippet: getSnippet(content, i + 1) };\n }\n }\n return null;\n },\n },\n\n // ── GitHub Actions ──\n {\n id: \"CFG008\", title: \"GitHub Actions with Broad Permissions\", severity: \"high\",\n category: \"Configuration\", description: \"GitHub Actions with write-all or broad permissions can be exploited if a dependency is compromised.\",\n fix: \"Use minimal permissions: permissions: { contents: read }. Only grant what's needed.\",\n owasp: \"A01:2021\", cwe: \"CWE-250\",\n filePattern: /\\.github\\/workflows\\/.*\\.(yml|yaml)$/,\n check(content) {\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n if (/permissions\\s*:\\s*write-all/i.test(lines[i])) {\n return { line: i + 1, snippet: getSnippet(content, i + 1) };\n }\n }\n return null;\n },\n },\n {\n id: \"CFG009\", title: \"GitHub Actions Using Unpinned Action\", severity: \"medium\",\n category: \"Configuration\", description: \"Using actions with @main or @master instead of a pinned SHA allows supply chain attacks.\",\n fix: \"Pin actions to a specific SHA: uses: actions/checkout@abc123... instead of @main.\",\n owasp: \"A06:2021\", cwe: \"CWE-1395\",\n filePattern: /\\.github\\/workflows\\/.*\\.(yml|yaml)$/,\n check(content) {\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n if (/uses:\\s*\\S+@(?:main|master|dev|latest)\\s*$/i.test(lines[i])) {\n return { line: i + 1, snippet: getSnippet(content, i + 1) };\n }\n }\n return null;\n },\n },\n\n // ── Vite Config ──\n {\n id: \"CFG010\", title: \"Vite Server Open to Network\", severity: \"medium\",\n category: \"Configuration\", description: \"Vite dev server with host: true exposes it to the entire network.\",\n fix: \"Remove host: true or use host: '127.0.0.1' for local-only access during development.\",\n owasp: \"A05:2021\", cwe: \"CWE-668\",\n filePattern: /vite\\.config\\.(js|ts|mjs)$/,\n check(content) {\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n if (/host\\s*:\\s*true/.test(lines[i]) || /host\\s*:\\s*['\"]0\\.0\\.0\\.0['\"]/.test(lines[i])) {\n return { line: i + 1, snippet: getSnippet(content, i + 1) };\n }\n }\n return null;\n },\n },\n\n // ── .npmrc ──\n {\n id: \"CFG011\", title: \"NPM Auth Token in .npmrc\", severity: \"critical\",\n category: \"Secrets\", description: \"NPM auth tokens in committed .npmrc files expose registry credentials.\",\n fix: \"Remove the token and add .npmrc to .gitignore. Use NPM_TOKEN env var instead.\",\n owasp: \"A02:2021\", cwe: \"CWE-798\",\n filePattern: /\\.npmrc$/,\n check(content) {\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n if (/_authToken|_auth=|\\/\\/registry.*:_password/.test(lines[i])) {\n return { line: i + 1, snippet: getSnippet(content, i + 1) };\n }\n }\n return null;\n },\n },\n\n // ── ESLint Config ──\n {\n id: \"CFG012\", title: \"Security ESLint Rules Disabled\", severity: \"medium\",\n category: \"Configuration\", description: \"Disabling security-related ESLint rules removes an important safety net.\",\n fix: \"Re-enable security rules or use eslint-plugin-security for automated checks.\",\n owasp: \"A05:2021\", cwe: \"CWE-710\",\n filePattern: /\\.eslint(rc)?(\\.(js|json|yml|yaml|cjs|mjs))?$/,\n check(content) {\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n if (/no-eval|no-implied-eval|no-new-func|no-script-url|security\\/detect/i.test(lines[i]) && /[\"']off[\"']|:\\s*0/.test(lines[i])) {\n return { line: i + 1, snippet: getSnippet(content, i + 1) };\n }\n }\n return null;\n },\n },\n];\n\nexport function scanConfigs(files: { path: string; content: string }[]): Finding[] {\n const findings: Finding[] = [];\n\n for (const { path: filePath, content } of files) {\n for (const check of CONFIG_CHECKS) {\n if (!check.filePattern.test(filePath)) continue;\n\n const result = check.check(content, filePath);\n if (result) {\n findings.push({\n id: `${check.id}-${filePath}:${result.line}`,\n rule: check.id,\n severity: check.severity,\n title: check.title,\n description: check.description,\n file: filePath,\n line: result.line,\n snippet: result.snippet,\n fix: check.fix,\n category: check.category,\n source: \"custom\",\n owasp: check.owasp,\n cwe: check.cwe,\n });\n }\n }\n }\n\n return findings;\n}\n","/**\n * Multi-File Analysis Scanner\n * Analyzes relationships between files to detect cross-file vulnerabilities\n * that single-file scanners miss.\n */\n\nimport type { Finding } from \"../types.js\";\n\nfunction getSnippet(content: string, line: number): string {\n const lines = content.split(\"\\n\");\n const start = Math.max(0, line - 2);\n const end = Math.min(lines.length, line + 2);\n return lines.slice(start, end).map((l, i) => {\n const lineNum = start + i + 1;\n const prefix = lineNum === line ? \">\" : \" \";\n return `${prefix} ${String(lineNum).padStart(5)} | ${l}`;\n }).join(\"\\n\");\n}\n\ninterface FileInfo {\n path: string;\n content: string;\n}\n\nexport function scanMultiFile(files: FileInfo[]): Finding[] {\n const findings: Finding[] = [];\n\n // Build indexes\n const fileMap = new Map<string, string>();\n for (const f of files) {\n fileMap.set(f.path, f.content);\n }\n\n // ── Check 1: API routes without middleware protection ──\n // If there's a middleware file that handles auth, routes are protected.\n // But if routes exist WITHOUT middleware, they're exposed.\n const hasGlobalMiddleware = files.some(f =>\n /middleware\\.(ts|js)$/.test(f.path) &&\n /(?:auth|session|clerk|nextauth|getToken)/i.test(f.content)\n );\n const hasAuthModule = files.some(f =>\n /(?:auth|middleware)\\.(ts|js)$/i.test(f.path) &&\n /(?:requireAuth|isAuthenticated|authenticate|verify)/i.test(f.content)\n );\n\n // Check API route files for auth\n for (const f of files) {\n if (!/(?:\\/api\\/|routes?\\/|controllers?\\/)/i.test(f.path)) continue;\n if (/middleware/i.test(f.path)) continue;\n\n // Skip health/status endpoints\n if (/(?:health|status|ping|ready|live)\\.(?:ts|js)/i.test(f.path)) continue;\n\n const hasLocalAuth = /(?:requireAuth|isAuthenticated|authenticate|verify|getAuth|getSession|getServerSession|withAuth|jwt\\.verify|clerk)/i.test(f.content);\n const hasAuthImport = /import.*(?:auth|session|middleware|verify|clerk)/i.test(f.content);\n\n if (!hasLocalAuth && !hasAuthImport && !hasGlobalMiddleware) {\n // Only flag if the file has actual route handlers\n if (/\\.(get|post|put|delete|patch)\\s*\\(|export\\s+(?:async\\s+)?function\\s+(?:GET|POST|PUT|DELETE|PATCH)/i.test(f.content)) {\n const line = f.content.split(\"\\n\").findIndex(l =>\n /\\.(get|post|put|delete|patch)\\s*\\(|export\\s+(?:async\\s+)?function\\s+(?:GET|POST|PUT|DELETE|PATCH)/i.test(l)\n ) + 1;\n findings.push({\n id: `MFA001-${f.path}:${line}`,\n rule: \"MFA001\",\n severity: \"high\",\n title: \"API Route Without Auth (Cross-File Check)\",\n description: \"This API route file has no authentication checks and no auth middleware was detected in the project.\",\n file: f.path,\n line,\n snippet: getSnippet(f.content, line),\n fix: \"Add authentication middleware or import your auth module. If using Next.js, create middleware.ts in your app root.\",\n category: \"Authentication\",\n source: \"custom\",\n owasp: \"A01:2021\",\n cwe: \"CWE-862\",\n });\n }\n }\n }\n\n // ── Check 2: .env file exists but .gitignore doesn't exclude it ──\n const hasEnvFile = files.some(f => /^\\.env$|\\/\\.env$/.test(f.path));\n const gitignore = files.find(f => f.path.endsWith(\".gitignore\"));\n if (hasEnvFile && gitignore) {\n if (!/^\\.env$/m.test(gitignore.content) && !/^\\*\\.env$/m.test(gitignore.content)) {\n findings.push({\n id: \"MFA002-.gitignore:1\",\n rule: \"MFA002\",\n severity: \"critical\",\n title: \".env File Not in .gitignore\",\n description: \"An .env file exists in the project but .gitignore doesn't exclude it. Secrets may be committed.\",\n file: \".gitignore\",\n line: 1,\n snippet: getSnippet(gitignore.content, 1),\n fix: \"Add .env to .gitignore: echo '.env' >> .gitignore\",\n category: \"Secrets\",\n source: \"custom\",\n owasp: \"A02:2021\",\n cwe: \"CWE-312\",\n });\n }\n }\n\n // ── Check 3: Database client without connection pooling ──\n const dbFiles = files.filter(f =>\n /(?:db|database|prisma|drizzle|sequelize|mongoose|knex)\\.(ts|js)$/i.test(f.path) ||\n /(?:createClient|createPool|createConnection|PrismaClient)/i.test(f.content)\n );\n for (const f of dbFiles) {\n // Check if DB client is created at module level (not in a function)\n if (/new PrismaClient/i.test(f.content)) {\n // Good pattern: globalThis.prisma = globalThis.prisma || new PrismaClient()\n if (!/globalThis|global\\./i.test(f.content)) {\n const line = f.content.split(\"\\n\").findIndex(l => /new PrismaClient/.test(l)) + 1;\n findings.push({\n id: `MFA003-${f.path}:${line}`,\n rule: \"MFA003\",\n severity: \"medium\",\n title: \"Database Client Not Cached (Connection Leak)\",\n description: \"Creating a new PrismaClient on every request leaks database connections. Use a singleton pattern.\",\n file: f.path,\n line,\n snippet: getSnippet(f.content, line),\n fix: \"Use singleton: globalThis.prisma = globalThis.prisma || new PrismaClient(). This prevents connection exhaustion in serverless.\",\n category: \"Configuration\",\n source: \"custom\",\n owasp: \"A05:2021\",\n cwe: \"CWE-400\",\n });\n }\n }\n }\n\n // ── Check 4: CORS origin mismatch ──\n // Check if CORS is configured but the origin doesn't match APP_URL or frontend URL\n for (const f of files) {\n if (!/(?:server|app|index|main)\\.(ts|js)$/i.test(f.path)) continue;\n const corsMatch = f.content.match(/origin\\s*:\\s*[\"'`](https?:\\/\\/[^\"'`]+)[\"'`]/);\n if (corsMatch) {\n const corsOrigin = corsMatch[1];\n if (corsOrigin.includes(\"localhost\") || corsOrigin.includes(\"127.0.0.1\")) {\n const line = f.content.split(\"\\n\").findIndex(l => l.includes(corsOrigin)) + 1;\n findings.push({\n id: `MFA004-${f.path}:${line}`,\n rule: \"MFA004\",\n severity: \"medium\",\n title: \"CORS Origin Set to Localhost\",\n description: \"CORS origin is hardcoded to localhost. This will block requests from your production frontend.\",\n file: f.path,\n line,\n snippet: getSnippet(f.content, line),\n fix: \"Use environment variable: origin: process.env.FRONTEND_URL || 'http://localhost:3000'\",\n category: \"Configuration\",\n source: \"custom\",\n owasp: \"A05:2021\",\n cwe: \"CWE-942\",\n });\n }\n }\n }\n\n // ── Check 5: Secret referenced but not in .env.example ──\n const envExample = files.find(f => /\\.env\\.example$|\\.env\\.sample$|\\.env\\.template$/.test(f.path));\n if (envExample) {\n const envVarsUsed = new Set<string>();\n for (const f of files) {\n if (/\\.(ts|js|tsx|jsx)$/i.test(f.path)) {\n const matches = f.content.matchAll(/process\\.env\\.([A-Z_][A-Z0-9_]*)/g);\n for (const m of matches) {\n envVarsUsed.add(m[1]);\n }\n }\n }\n const envVarsDocumented = new Set<string>();\n const exampleMatches = envExample.content.matchAll(/^([A-Z_][A-Z0-9_]*)=/gm);\n for (const m of exampleMatches) {\n envVarsDocumented.add(m[1]);\n }\n\n const undocumented = [...envVarsUsed].filter(v => !envVarsDocumented.has(v) && !v.startsWith(\"NODE_\") && v !== \"npm_\");\n if (undocumented.length > 0) {\n findings.push({\n id: `MFA005-${envExample.path}:1`,\n rule: \"MFA005\",\n severity: \"low\",\n title: \"Env Vars Used But Not in .env.example\",\n description: `These environment variables are used in code but missing from .env.example: ${undocumented.slice(0, 5).join(\", \")}${undocumented.length > 5 ? ` (+${undocumented.length - 5} more)` : \"\"}`,\n file: envExample.path,\n line: 1,\n snippet: getSnippet(envExample.content, 1),\n fix: \"Add missing variables to .env.example so team members know which env vars are needed.\",\n category: \"Configuration\",\n source: \"custom\",\n owasp: \"A05:2021\",\n cwe: \"CWE-1188\",\n });\n }\n }\n\n // ── Check 6: Frontend fetching HTTP API in production code ──\n for (const f of files) {\n if (!/\\.(tsx|jsx|ts|js)$/i.test(f.path)) continue;\n if (/(?:test|spec|mock|fixture)/i.test(f.path)) continue;\n\n const httpFetches = f.content.matchAll(/fetch\\s*\\(\\s*[\"'`](http:\\/\\/(?!localhost|127\\.0\\.0\\.1)[^\"'`]+)[\"'`]/g);\n for (const m of httpFetches) {\n const line = f.content.substring(0, m.index).split(\"\\n\").length;\n findings.push({\n id: `MFA006-${f.path}:${line}`,\n rule: \"MFA006\",\n severity: \"high\",\n title: \"Frontend Fetching Over HTTP (Not HTTPS)\",\n description: `Fetching from ${m[1].substring(0, 40)}... over HTTP exposes data to interception.`,\n file: f.path,\n line,\n snippet: getSnippet(f.content, line),\n fix: \"Use HTTPS for all API calls in production.\",\n category: \"Configuration\",\n source: \"custom\",\n owasp: \"A02:2021\",\n cwe: \"CWE-319\",\n });\n }\n }\n\n return findings;\n}\n","import chalk from \"chalk\";\nimport Table from \"cli-table3\";\nimport type { Finding, ScanResult, Severity } from \"../types.js\";\nimport { calculateGrade, detectFramework, type SecurityGrade } from \"../scanners/custom-rules.js\";\n\nconst SEVERITY_COLORS: Record<Severity, (text: string) => string> = {\n critical: chalk.bgRed.white.bold,\n high: chalk.red.bold,\n medium: chalk.yellow.bold,\n low: chalk.blue,\n info: chalk.gray,\n};\n\nconst SEVERITY_ICONS: Record<Severity, string> = {\n critical: \"!!!\",\n high: \" !! \",\n medium: \" ! \",\n low: \" - \",\n info: \" i \",\n};\n\nconst SEVERITY_ORDER: Record<Severity, number> = {\n critical: 0,\n high: 1,\n medium: 2,\n low: 3,\n info: 4,\n};\n\nconst GRADE_COLORS: Record<SecurityGrade, (text: string) => string> = {\n \"A+\": chalk.green.bold,\n \"A\": chalk.green.bold,\n \"B\": chalk.cyan.bold,\n \"C\": chalk.yellow.bold,\n \"D\": chalk.red.bold,\n \"F\": chalk.bgRed.white.bold,\n};\n\nexport function renderTerminalReport(result: ScanResult, files?: { path: string; content: string }[]): void {\n const { findings, filesScanned, duration } = result;\n\n // Header\n console.log(\"\");\n console.log(chalk.bold.cyan(\" xploitscan\") + chalk.gray(\" — security scan results\"));\n console.log(chalk.gray(\" \" + \"─\".repeat(50)));\n console.log(\"\");\n\n // Framework detection\n if (files && files.length > 0) {\n const frameworks = detectFramework(files);\n if (frameworks.length > 0 && frameworks[0] !== \"unknown\") {\n console.log(chalk.gray(\" Frameworks: \") + chalk.white(frameworks.join(\", \")));\n }\n }\n\n // Grade + Benchmark\n const GRADE_PERCENTILES: Record<string, number> = { \"A+\": 98, \"A\": 90, \"B\": 70, \"C\": 45, \"D\": 20, \"F\": 5 };\n const { grade, score, summary } = calculateGrade(findings, filesScanned);\n const gradeColor = GRADE_COLORS[grade];\n const percentile = GRADE_PERCENTILES[grade] ?? 50;\n console.log(chalk.gray(\" Security Grade: \") + gradeColor(` ${grade} `) + chalk.gray(` (${score}/100) — ${summary}`));\n console.log(chalk.gray(` Benchmark: More secure than ${percentile}% of projects scanned`));\n console.log(\"\");\n\n if (findings.length === 0) {\n console.log(chalk.green.bold(\" No vulnerabilities found!\"));\n console.log(chalk.gray(` Scanned ${filesScanned} files in ${(duration / 1000).toFixed(1)}s`));\n console.log(\"\");\n return;\n }\n\n // Sort by severity\n const sorted = [...findings].sort(\n (a, b) => SEVERITY_ORDER[a.severity] - SEVERITY_ORDER[b.severity],\n );\n\n // Summary table\n const counts: Record<Severity, number> = { critical: 0, high: 0, medium: 0, low: 0, info: 0 };\n for (const f of findings) counts[f.severity]++;\n\n const summaryParts: string[] = [];\n if (counts.critical > 0) summaryParts.push(chalk.bgRed.white.bold(` ${counts.critical} CRITICAL `));\n if (counts.high > 0) summaryParts.push(chalk.red.bold(`${counts.high} high`));\n if (counts.medium > 0) summaryParts.push(chalk.yellow.bold(`${counts.medium} medium`));\n if (counts.low > 0) summaryParts.push(chalk.blue(`${counts.low} low`));\n if (counts.info > 0) summaryParts.push(chalk.gray(`${counts.info} info`));\n\n console.log(` Found ${chalk.bold(findings.length.toString())} issues: ${summaryParts.join(chalk.gray(\" | \"))}`);\n console.log(chalk.gray(` Scanned ${filesScanned} files in ${(duration / 1000).toFixed(1)}s`));\n console.log(\"\");\n\n // Individual findings\n for (const finding of sorted) {\n const severityLabel = SEVERITY_COLORS[finding.severity](\n ` ${finding.severity.toUpperCase()} `,\n );\n const sourceLabel = finding.source === \"ai\"\n ? chalk.magenta(\" [AI] \")\n : finding.source === \"dependency\"\n ? chalk.cyan(\" [DEP] \")\n : finding.source === \"entropy\"\n ? chalk.yellow(\" [ENTROPY] \")\n : finding.source === \"config\"\n ? chalk.blue(\" [CFG] \")\n : finding.source === \"multi-file\"\n ? chalk.green(\" [CROSS-FILE] \")\n : chalk.gray(` [${finding.rule}] `);\n const confidenceLabel = finding.confidence\n ? chalk.gray(` (${finding.confidence} confidence)`)\n : \"\";\n\n const complianceTags = [\n finding.owasp ? chalk.yellow(`[${finding.owasp}]`) : \"\",\n finding.cwe ? chalk.blue(`[${finding.cwe}]`) : \"\",\n ].filter(Boolean).join(\" \");\n console.log(` ${severityLabel}${sourceLabel}${chalk.bold(finding.title)} ${complianceTags}${confidenceLabel}`);\n console.log(chalk.gray(` ${finding.file}:${finding.line}`));\n console.log(\"\");\n\n // Description\n console.log(chalk.white(` ${finding.description}`));\n console.log(\"\");\n\n // Code snippet\n if (finding.snippet) {\n const snippetLines = finding.snippet.split(\"\\n\");\n for (const line of snippetLines) {\n if (line.startsWith(\">\")) {\n console.log(chalk.red(` ${line}`));\n } else {\n console.log(chalk.gray(` ${line}`));\n }\n }\n console.log(\"\");\n }\n\n // Fix suggestion\n if (finding.fix) {\n console.log(chalk.green(` Fix: ${finding.fix}`));\n console.log(\"\");\n }\n\n console.log(chalk.gray(\" \" + \"─\".repeat(50)));\n console.log(\"\");\n }\n\n // OWASP Top 10 Summary\n const owaspFindings = findings.filter(f => f.owasp);\n if (owaspFindings.length > 0) {\n const owaspCats: Record<string, { name: string; count: number }> = {\n \"A01:2021\": { name: \"Broken Access Control\", count: 0 },\n \"A02:2021\": { name: \"Cryptographic Failures\", count: 0 },\n \"A03:2021\": { name: \"Injection\", count: 0 },\n \"A04:2021\": { name: \"Insecure Design\", count: 0 },\n \"A05:2021\": { name: \"Security Misconfiguration\", count: 0 },\n \"A06:2021\": { name: \"Vulnerable Components\", count: 0 },\n \"A07:2021\": { name: \"Auth Failures\", count: 0 },\n \"A08:2021\": { name: \"Data Integrity\", count: 0 },\n \"A09:2021\": { name: \"Logging Failures\", count: 0 },\n \"A10:2021\": { name: \"SSRF\", count: 0 },\n };\n for (const f of owaspFindings) {\n if (f.owasp && owaspCats[f.owasp]) owaspCats[f.owasp].count++;\n }\n console.log(chalk.bold(\" OWASP Top 10 Compliance\"));\n for (const [id, { name, count }] of Object.entries(owaspCats)) {\n const status = count > 0 ? chalk.red(`${count} issue${count > 1 ? \"s\" : \"\"}`) : chalk.green(\"PASS\");\n console.log(chalk.gray(` ${id} ${name}: `) + status);\n }\n console.log(\"\");\n }\n\n // Footer\n if (counts.critical > 0) {\n console.log(\n chalk.bgRed.white.bold(\" ACTION REQUIRED \") +\n chalk.red.bold(` ${counts.critical} critical issue${counts.critical > 1 ? \"s\" : \"\"} found. Fix these before deploying.`),\n );\n } else if (counts.high > 0) {\n console.log(\n chalk.yellow.bold(` Recommendation: Address the ${counts.high} high-severity issue${counts.high > 1 ? \"s\" : \"\"} before going to production.`),\n );\n }\n\n console.log(\"\");\n}\n","import type { ScanResult } from \"../types.js\";\n\nexport function renderJsonReport(result: ScanResult): void {\n console.log(JSON.stringify(result, null, 2));\n}\n","import type { Finding, ScanResult, Severity } from \"../types.js\";\n\nconst SEVERITY_TO_SARIF: Record<Severity, string> = {\n critical: \"error\",\n high: \"error\",\n medium: \"warning\",\n low: \"note\",\n info: \"none\",\n};\n\nconst SEVERITY_TO_LEVEL: Record<Severity, number> = {\n critical: 10.0,\n high: 8.0,\n medium: 5.0,\n low: 3.0,\n info: 1.0,\n};\n\ninterface SarifOutput {\n $schema: string;\n version: string;\n runs: Array<{\n tool: {\n driver: {\n name: string;\n version: string;\n informationUri: string;\n rules: Array<{\n id: string;\n shortDescription: { text: string };\n fullDescription: { text: string };\n defaultConfiguration: { level: string };\n properties: { security_severity: string; tags: string[] };\n }>;\n };\n };\n results: Array<{\n ruleId: string;\n ruleIndex: number;\n level: string;\n message: { text: string };\n locations: Array<{\n physicalLocation: {\n artifactLocation: { uri: string };\n region: {\n startLine: number;\n startColumn?: number;\n };\n };\n }>;\n fixes?: Array<{\n description: { text: string };\n }>;\n }>;\n }>;\n}\n\nexport function renderSarifReport(result: ScanResult): void {\n // Collect unique rules\n const ruleMap = new Map<string, Finding>();\n for (const f of result.findings) {\n if (!ruleMap.has(f.rule)) {\n ruleMap.set(f.rule, f);\n }\n }\n\n const rules = Array.from(ruleMap.entries()).map(([id, f]) => ({\n id,\n shortDescription: { text: f.title },\n fullDescription: { text: f.description },\n defaultConfiguration: { level: SEVERITY_TO_SARIF[f.severity] },\n properties: {\n security_severity: SEVERITY_TO_LEVEL[f.severity].toFixed(1),\n tags: [\"security\", f.category.toLowerCase().replace(/\\s+/g, \"-\")],\n },\n }));\n\n const ruleIndex = new Map(rules.map((r, i) => [r.id, i]));\n\n const sarif: SarifOutput = {\n $schema: \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json\",\n version: \"2.1.0\",\n runs: [\n {\n tool: {\n driver: {\n name: \"xploitscan\",\n version: \"0.1.0\",\n informationUri: \"https://github.com/bgage72590/xploitscan\",\n rules,\n },\n },\n results: result.findings.map((f) => {\n const entry: SarifOutput[\"runs\"][0][\"results\"][0] = {\n ruleId: f.rule,\n ruleIndex: ruleIndex.get(f.rule) ?? 0,\n level: SEVERITY_TO_SARIF[f.severity],\n message: {\n text: `${f.title}: ${f.description}`,\n },\n locations: [\n {\n physicalLocation: {\n artifactLocation: { uri: f.file },\n region: {\n startLine: f.line,\n ...(f.column ? { startColumn: f.column } : {}),\n },\n },\n },\n ],\n };\n\n if (f.fix) {\n entry.fixes = [{ description: { text: f.fix } }];\n }\n\n return entry;\n }),\n },\n ],\n };\n\n console.log(JSON.stringify(sarif, null, 2));\n}\n","import { createServer } from \"node:http\";\nimport { URL } from \"node:url\";\nimport { randomUUID } from \"node:crypto\";\nimport { execFile } from \"node:child_process\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { storeToken, clearToken, getStoredToken, syncUser } from \"../utils/api.js\";\n\nconst CLERK_PUBLISHABLE_KEY = process.env.CLERK_PUBLISHABLE_KEY ?? \"\";\n\n/**\n * Opens a browser-based login flow.\n * 1. Starts a local HTTP server on a random port\n * 2. Opens the Clerk sign-in page with redirect back to local server\n * 3. Receives the token via redirect callback\n * 4. Stores the token locally\n */\nexport async function loginCommand(): Promise<void> {\n const existing = getStoredToken();\n if (existing) {\n console.log(chalk.yellow(`Already logged in as ${existing.email}`));\n console.log(chalk.gray(\"Run `xploitscan auth logout` first to switch accounts.\"));\n return;\n }\n\n const spinner = ora(\"Waiting for browser login...\").start();\n\n // Start local callback server\n const { token, email, userId } = await waitForBrowserLogin();\n\n spinner.text = \"Syncing account...\";\n\n // Store token\n storeToken({\n token,\n userId,\n email,\n expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000, // 7 days\n });\n\n // Sync user with API\n const user = await syncUser();\n spinner.stop();\n\n console.log(chalk.green(`Logged in as ${email}`));\n if (user) {\n console.log(chalk.gray(`Plan: ${user.plan}`));\n }\n}\n\nexport async function logoutCommand(): Promise<void> {\n const existing = getStoredToken();\n if (!existing) {\n console.log(chalk.gray(\"Not logged in.\"));\n return;\n }\n\n clearToken();\n console.log(chalk.green(\"Logged out successfully.\"));\n}\n\nexport async function whoamiCommand(): Promise<void> {\n const token = getStoredToken();\n if (!token) {\n console.log(chalk.gray(\"Not logged in. Run `xploitscan auth login` to authenticate.\"));\n return;\n }\n\n console.log(chalk.cyan(`Email: ${token.email}`));\n console.log(chalk.gray(`User ID: ${token.userId}`));\n\n const user = await syncUser();\n if (user) {\n const planBadge = user.plan === \"pro\"\n ? chalk.bgGreen.black(\" PRO \")\n : chalk.bgGray.white(\" FREE \");\n console.log(`Plan: ${planBadge}`);\n }\n}\n\nasync function waitForBrowserLogin(): Promise<{\n token: string;\n email: string;\n userId: string;\n}> {\n return new Promise((resolve, reject) => {\n const expectedState = randomUUID();\n\n const server = createServer((req, res) => {\n if (!req.url) {\n res.writeHead(400);\n res.end(\"Bad request\");\n return;\n }\n\n const url = new URL(req.url, `http://localhost`);\n\n if (url.pathname === \"/callback\") {\n const token = url.searchParams.get(\"token\");\n const email = url.searchParams.get(\"email\");\n const userId = url.searchParams.get(\"user_id\");\n const state = url.searchParams.get(\"state\");\n\n if (!state || state !== expectedState) {\n res.writeHead(403);\n res.end(\"Invalid state parameter — possible CSRF attack.\");\n return;\n }\n\n if (token && email && userId) {\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(`\n <html>\n <body style=\"font-family: system-ui; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #0a0a0f; color: #e0e0e0;\">\n <div style=\"text-align: center;\">\n <h1 style=\"color: #00d4ff;\">xploitscan</h1>\n <p style=\"color: #4ade80; font-size: 1.2rem;\">Login successful!</p>\n <p style=\"color: #888;\">You can close this tab and return to your terminal.</p>\n </div>\n </body>\n </html>\n `);\n\n server.close();\n resolve({ token, email, userId });\n } else {\n res.writeHead(400);\n res.end(\"Missing parameters\");\n }\n } else if (url.pathname === \"/login\") {\n // Serve a simple login page that redirects to Clerk\n const callbackUrl = `http://localhost:${(server.address() as { port: number }).port}/callback`;\n\n // Development-only bypass — requires both env vars to be explicitly set\n if (process.env.NODE_ENV === \"development\" && process.env.XPLOITSCAN_DEV_AUTH === \"true\") {\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(`\n <html>\n <body style=\"font-family: system-ui; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #0a0a0f; color: #e0e0e0;\">\n <div style=\"text-align: center;\">\n <h1 style=\"color: #00d4ff;\">xploitscan</h1>\n <p>Redirecting to login (dev mode)...</p>\n <script>\n const params = new URLSearchParams({\n token: 'dev_token_' + Date.now(),\n email: 'dev@xploitscan.com',\n user_id: 'user_dev_' + Date.now(),\n state: '${expectedState}'\n });\n setTimeout(() => {\n window.location.href = '/callback?' + params.toString();\n }, 1000);\n </script>\n </div>\n </body>\n </html>\n `);\n } else {\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(`\n <html>\n <body style=\"font-family: system-ui; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #0a0a0f; color: #e0e0e0;\">\n <div style=\"text-align: center;\">\n <h1 style=\"color: #00d4ff;\">xploitscan</h1>\n <p>Redirecting to login...</p>\n <p style=\"color: #888; font-size: 0.85rem;\">If not redirected, <a href=\"#\" style=\"color: #00d4ff;\">click here</a>.</p>\n </div>\n </body>\n </html>\n `);\n }\n } else {\n res.writeHead(302, { Location: \"/login\" });\n res.end();\n }\n });\n\n // Listen on random available port\n server.listen(0, \"127.0.0.1\", () => {\n const addr = server.address() as { port: number };\n const loginUrl = `http://localhost:${addr.port}/login`;\n\n console.log(chalk.cyan(`\\nOpen this URL in your browser to log in:`));\n console.log(chalk.bold.underline(loginUrl));\n console.log(\"\");\n\n // Try to open browser automatically\n const openCmd = process.platform === \"darwin\" ? \"open\" : process.platform === \"win32\" ? \"start\" : \"xdg-open\";\n execFile(openCmd, [loginUrl], () => {});\n });\n\n // Timeout after 5 minutes\n setTimeout(() => {\n server.close();\n reject(new Error(\"Login timed out. Please try again.\"));\n }, 5 * 60 * 1000);\n });\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA,SAAS,eAAe;;;ACAxB,SAAS,WAAAA,UAAS,QAAAC,aAAsB;AACxC,SAAS,SAAS,eAAe;AACjC,OAAO,SAAS;AAChB,OAAOC,YAAW;;;ACHlB,OAAO,QAAQ;AACf,OAAO,YAAY;AACnB,SAAS,cAAc,kBAAkB;AACzC,SAAS,MAAM,eAAe;AAE9B,IAAM,oBAAoB;AAAA,EACxB;AAAA,EAAM;AAAA,EAAO;AAAA,EAAM;AAAA,EAAO;AAAA,EAAO;AAAA,EACjC;AAAA,EAAO;AAAA,EAAU;AAAA,EACjB;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAQ;AAAA,EAChC;AAAA,EAAS;AAAA,EAAM;AAAA,EAAO;AAAA,EAAQ;AAAA,EAC9B;AAAA,EAAK;AAAA,EAAO;AAAA,EACZ;AAAA,EAAM;AAAA,EAAQ;AAAA,EACd;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAQ;AAAA,EACtC;AAAA,EAAQ;AAAA,EAAO;AAAA,EACf;AAAA,EAAc;AAAA,EAAO;AAAA,EAAO;AAAA,EAC5B;AAAA,EAAM;AAAA,EAAO;AAAA,EACb;AAAA,EAAO;AAAA,EAAS;AAAA,EAChB;AAAA,EACA;AAAA,EAAK;AAAA,EAAO;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAC9B;AAAA,EAAS;AAAA,EACT;AAAA,EAAU;AAAA,EAAS;AAAA,EAAW;AAAA,EAAgB;AAAA,EAAS;AACzD;AAEA,IAAM,mBAAmB;AAAA,EACvB;AAAA,EAAc;AAAA,EAAY;AAAA,EAAW;AAAA,EACrC;AAAA,EAAgB;AAAA,EAAc;AAAA,EAAU;AAAA,EAAoB;AAAA,EAC5D;AAAA,EAAkB;AAAA,EAAmB;AAAA,EAAkB;AAAA,EACvD;AAAA,EAAiB;AAAA,EAAe;AAAA,EAChC;AAAA,EAAY;AAAA,EAAiB;AAAA,EAC7B;AAAA,EAAiB;AAAA,EACjB;AAAA,EAAqB;AAAA,EACrB;AAAA,EAAY;AAAA,EAAa;AAAA,EACzB;AACF;AAEA,IAAM,gBAAgB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,eAAsB,aAAa,WAAsC;AACvE,QAAM,KAAK,OAAO,QAAQ;AAG1B,QAAM,gBAAgB,KAAK,WAAW,YAAY;AAClD,MAAI,WAAW,aAAa,GAAG;AAC7B,UAAM,mBAAmB,aAAa,eAAe,OAAO;AAC5D,OAAG,IAAI,gBAAgB;AAAA,EACzB;AAGA,QAAM,uBAAuB,KAAK,WAAW,mBAAmB;AAChE,MAAI,WAAW,oBAAoB,GAAG;AACpC,UAAM,0BAA0B,aAAa,sBAAsB,OAAO;AAC1E,OAAG,IAAI,uBAAuB;AAAA,EAChC;AAGA,KAAG,IAAI,aAAa;AAEpB,QAAM,WAAW,kBAAkB,IAAI,CAAC,QAAQ,QAAQ,GAAG,EAAE;AAE7D,WAAS,KAAK,UAAU;AAExB,aAAW,QAAQ,kBAAkB;AACnC,aAAS,KAAK,MAAM,IAAI,EAAE;AAAA,EAC5B;AAEA,QAAM,QAAQ,MAAM,GAAG,UAAU;AAAA,IAC/B,KAAK;AAAA,IACL,UAAU;AAAA,IACV,KAAK;AAAA,IACL,WAAW;AAAA,IACX,QAAQ,cAAc,IAAI,CAAC,MAAM,MAAM,CAAC,EAAE;AAAA,EAC5C,CAAC;AAGD,SAAO,MAAM,OAAO,CAAC,SAAS,CAAC,GAAG,QAAQ,IAAI,CAAC;AACjD;AAEO,SAAS,iBACd,WACA,UACe;AACf,MAAI;AACF,UAAM,WAAW,QAAQ,KAAK,WAAW,QAAQ,CAAC;AAClD,QAAI,CAAC,SAAS,WAAW,QAAQ,SAAS,CAAC,GAAG;AAC5C,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AACA,WAAO,aAAa,UAAU,OAAO;AAAA,EACvC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,WACd,SACA,MACA,eAAe,GACP;AACR,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,QAAM,QAAQ,KAAK,IAAI,GAAG,OAAO,IAAI,YAAY;AACjD,QAAM,MAAM,KAAK,IAAI,MAAM,QAAQ,OAAO,YAAY;AAEtD,SAAO,MACJ,MAAM,OAAO,GAAG,EAChB,IAAI,CAAC,GAAG,MAAM;AACb,UAAM,UAAU,QAAQ,IAAI;AAC5B,UAAM,SAAS,YAAY,OAAO,MAAM;AACxC,WAAO,GAAG,MAAM,IAAI,QAAQ,SAAS,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC;AAAA,EAC3D,CAAC,EACA,KAAK,IAAI;AACd;;;ACjIA,SAAS,mBAAmB;AAC5B,SAAS,gBAAAC,qBAAoB;AAC7B,SAAS,QAAAC,aAAY;AAgDrB,IAAM,WAA6B;AAAA,EACjC,SAAS,CAAC;AAAA,EACV,IAAI;AAAA,EACJ,UAAU;AAAA,EACV,cAAc,CAAC;AACjB;AAEA,SAAS,iBAAiB,WAA8C;AACtE,MAAI;AACF,UAAM,SAASA,MAAK,WAAW,eAAe;AAC9C,UAAM,UAAUD,cAAa,QAAQ,OAAO;AAC5C,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,kBACP,MACA,IACkB;AAClB,QAAM,SAAS,EAAE,GAAG,KAAK;AAGzB,MAAI,GAAG,OAAO;AACZ,QAAI,GAAG,MAAM,SAAS;AACpB,aAAO,eAAe;AAAA,QACpB,GAAG,oBAAI,IAAI,CAAC,GAAI,OAAO,gBAAgB,CAAC,GAAI,GAAG,GAAG,MAAM,OAAO,CAAC;AAAA,MAClE;AAAA,IACF;AACA,QAAI,GAAG,MAAM,kBAAkB;AAC7B,aAAO,mBAAmB;AAAA,QACxB,GAAI,OAAO,oBAAoB,CAAC;AAAA,QAChC,GAAG,GAAG,MAAM;AAAA,MACd;AAAA,IACF;AAAA,EACF;AAGA,MAAI,GAAG,MAAM;AACX,QAAI,GAAG,KAAK,SAAS;AACnB,aAAO,UAAU;AAAA,QACf,GAAG,oBAAI,IAAI,CAAC,GAAI,OAAO,WAAW,CAAC,GAAI,GAAG,GAAG,KAAK,OAAO,CAAC;AAAA,MAC5D;AAAA,IACF;AACA,QAAI,GAAG,KAAK,gBAAgB,QAAW;AACrC,aAAO,cAAc,GAAG,KAAK;AAAA,IAC/B;AACA,QAAI,GAAG,KAAK,YAAY;AACtB,aAAO,aAAa;AAAA,QAClB,GAAG,oBAAI,IAAI,CAAC,GAAI,OAAO,cAAc,CAAC,GAAI,GAAG,GAAG,KAAK,UAAU,CAAC;AAAA,MAClE;AAAA,IACF;AAAA,EACF;AAGA,MAAI,GAAG,QAAQ;AACb,QAAI,GAAG,OAAO,WAAW,QAAW;AAClC,aAAO,SAAS,GAAG,OAAO;AAAA,IAC5B;AACA,QAAI,GAAG,OAAO,YAAY,QAAW;AACnC,aAAO,UAAU,GAAG,OAAO;AAAA,IAC7B;AAAA,EACF;AAGA,MAAI,GAAG,OAAO;AACZ,WAAO,QAAQ;AAAA,MACb,GAAI,OAAO,SAAS,CAAC;AAAA,MACrB,GAAG,GAAG;AAAA,IACR;AAAA,EACF;AAEA,SAAO;AACT;AAEA,eAAsB,WACpB,WAC2B;AAC3B,QAAM,WAAW,YAAY,YAAY;AAEzC,MAAI,SAAS,EAAE,GAAG,SAAS;AAE3B,MAAI;AACF,UAAM,SAAS,MAAM,SAAS,OAAO,SAAS;AAC9C,QAAI,UAAU,OAAO,QAAQ;AAC3B,eAAS,EAAE,GAAG,UAAU,GAAG,OAAO,OAAO;AAAA,IAC3C;AAAA,EACF,QAAQ;AAAA,EAER;AAGA,QAAM,KAAK,iBAAiB,SAAS;AACrC,MAAI,IAAI;AACN,aAAS,kBAAkB,QAAQ,EAAE;AAAA,EACvC;AAEA,SAAO;AACT;;;AC5IA,IAAM,oBAAoB;AAE1B,SAAS,WAAW,UAA2B;AAC7C,SAAO,kBAAkB,KAAK,QAAQ;AACxC;AAGA,SAAS,cAAc,SAAiB,YAA6B;AACnE,QAAM,YAAY,QAAQ,YAAY,MAAM,aAAa,CAAC,IAAI;AAC9D,QAAM,WAAW,QAAQ,UAAU,WAAW,QAAQ,QAAQ,MAAM,UAAU,CAAC,EAAE,UAAU;AAC3F,SACE,SAAS,WAAW,IAAI,KACxB,SAAS,WAAW,GAAG,KACvB,SAAS,WAAW,GAAG,KACvB,SAAS,WAAW,IAAI,KACxB,SAAS,WAAW,MAAM,KAC1B,SAAS,WAAW,GAAG,KAAK,SAAS,SAAS,KAAK,eAAe,KAAK,EAAE;AAE7E;AAIA,SAAS,mBAAmB,SAAiB,YAA6B;AACxE,QAAM,YAAY,QAAQ,YAAY,MAAM,aAAa,CAAC,IAAI;AAC9D,QAAM,WAAW,QAAQ,UAAU,WAAW,QAAQ,QAAQ,MAAM,UAAU,CAAC;AAE/E,SAAO,gFAAgF,KAAK,QAAQ,KAClG,0FAA0F,KAAK,QAAQ;AAC3G;AAaA,SAAS,YACP,SACA,SACA,MACA,UACA,aACa;AACb,QAAM,UAAuB,CAAC;AAC9B,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,MAAI;AACJ,QAAM,KAAK,IAAI,OAAO,QAAQ,QAAQ,QAAQ,MAAM,SAAS,GAAG,IAAI,QAAQ,QAAQ,GAAG,QAAQ,KAAK,GAAG;AAEvG,UAAQ,IAAI,GAAG,KAAK,OAAO,OAAO,MAAM;AAEtC,QAAI,cAAc,SAAS,EAAE,KAAK,EAAG;AAErC,QAAI,mBAAmB,SAAS,EAAE,KAAK,EAAG;AAE1C,UAAM,UAAU,QAAQ,UAAU,GAAG,EAAE,KAAK,EAAE,MAAM,IAAI,EAAE;AAC1D,YAAQ,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,OAAO,KAAK;AAAA,MACZ,UAAU,KAAK;AAAA,MACf,UAAU,KAAK;AAAA,MACf,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,WAAW,SAAS,OAAO;AAAA,MACpC,KAAK,cAAc,CAAC;AAAA,IACtB,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAMA,IAAM,mBAA+B;AAAA,EACnC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AAEvB,QAAI,SAAS,SAAS,UAAU,KAAK,SAAS,SAAS,WAAW,EAAG,QAAO,CAAC;AAC7E,QAAI,WAAW,QAAQ,EAAG,QAAO,CAAC;AAClC,QAAI,SAAS,MAAM,sBAAsB,EAAG,QAAO,CAAC;AAEpD,UAAM,WAAW;AAAA;AAAA,MAEf;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA,IACF;AAEA,UAAM,UAAuB,CAAC;AAC9B,eAAW,WAAW,UAAU;AAC9B,YAAM,aAAa;AAAA,QAAY;AAAA,QAAS;AAAA,QAAS;AAAA,QAAkB;AAAA,QAAU,MAC3E;AAAA,MACF;AAEA,iBAAWE,OAAM,YAAY;AAC3B,cAAM,WAAW,QAAQ,MAAM,IAAI,EAAEA,IAAG,OAAO,CAAC,KAAK;AAErD,cAAM,UAAU,SAAS,UAAU;AACnC,YAAI,QAAQ,WAAW,IAAI,KAAK,QAAQ,WAAW,GAAG,EAAG;AAEzD,cAAM,cAAc,SAAS,MAAM,4BAA4B;AAC/D,YAAI,eAAe,YAAY,CAAC,EAAE,SAAS,GAAI;AAC/C,gBAAQ,KAAKA,GAAE;AAAA,MACjB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAEA,IAAM,iBAA6B;AAAA,EACjC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AAEvB,QAAI,CAAC,SAAS,MAAM,qBAAqB,KAAK,SAAS,SAAS,SAAS,EAAG,QAAO,CAAC;AAEpF,UAAM,aAAa,0DAA0D,KAAK,OAAO;AACzF,QAAI,CAAC,WAAY,QAAO,CAAC;AAEzB,WAAO,CAAC;AAAA,MACN,MAAM;AAAA,MACN,OAAO,eAAe;AAAA,MACtB,UAAU;AAAA,MACV,UAAU;AAAA,MACV,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,WAAW,SAAS,CAAC;AAAA,MAC9B,KAAK,qGAAqG;AAAA,IAC5G,CAAC;AAAA,EACH;AACF;AAEA,IAAM,wBAAoC;AAAA,EACxC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AAEvB,UAAM,aAAa,oDAAoD,KAAK,QAAQ,KACjE,SAAS,SAAS,SAAS;AAC9C,QAAI,CAAC,WAAY,QAAO,CAAC;AAGzB,UAAM,gBAAgB;AAAA;AAAA,MAEpB;AAAA;AAAA,MAEA;AAAA,IACF;AAGA,QAAI,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,MAAM,EAAG,QAAO,CAAC;AAEjG,UAAM,eAAe;AAAA,MACnB;AAAA,MAAS;AAAA,MAAY;AAAA,MAAQ;AAAA,MAAW;AAAA,MACxC;AAAA,MAAY;AAAA,MAAgB;AAAA,MAAoB;AAAA,MAChD;AAAA,MAAU;AAAA,MAAmB;AAAA,MAAqB;AAAA,MAClD;AAAA,MAAY;AAAA,MAAU;AAAA,MAAgB;AAAA,MAAkB;AAAA,MACxD;AAAA,MAAa;AAAA,MAAmB;AAAA,IAClC;AAEA,UAAM,UAAU,aAAa,KAAK,CAAC,MAAM,EAAE,KAAK,OAAO,CAAC;AACxD,QAAI,QAAS,QAAO,CAAC;AAErB,UAAM,UAAuB,CAAC;AAC9B,eAAW,WAAW,eAAe;AACnC,cAAQ;AAAA,QACN,GAAG;AAAA,UAAY;AAAA,UAAS;AAAA,UAAS;AAAA,UAAuB;AAAA,UAAU,MAChE;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAEA,IAAM,gBAA4B;AAAA,EAChC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,UAAM,UAAuB,CAAC;AAG9B,QACE,0CAA0C,KAAK,OAAO,MACrD,qBAAqB,KAAK,OAAO,KAAK,SAAS,MAAM,yBAAyB,IAC/E;AACA,cAAQ;AAAA,QACN,GAAG;AAAA,UACD;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,MAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAGA,QAAI,gBAAgB,KAAK,OAAO,KAAK,WAAW,KAAK,OAAO,GAAG;AAC7D,YAAM,eAAe,oCAAoC,KAAK,OAAO;AACrE,UAAI,cAAc;AAChB,gBAAQ;AAAA,UACN,GAAG;AAAA,YACD;AAAA,YACA;AAAA,YACA,EAAE,GAAG,eAAe,OAAO,+BAA+B;AAAA,YAC1D;AAAA,YACA,MAAM;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;AAEA,IAAM,2BAAuC;AAAA,EAC3C,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AAEvB,QAAI,CAAC,kBAAkB,KAAK,OAAO,EAAG,QAAO,CAAC;AAE9C,UAAM,kBAAkB,WAAW,KAAK,QAAQ,KAC9C,6BAA6B,KAAK,OAAO;AAC3C,QAAI,CAAC,gBAAiB,QAAO,CAAC;AAG9B,UAAM,kBAAkB,+DAA+D,KAAK,OAAO;AACnG,QAAI,gBAAiB,QAAO,CAAC;AAE7B,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MACE;AAAA,IACJ;AAAA,EACF;AACF;AAEA,IAAM,eAA2B;AAAA,EAC/B,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,UAAM,WAAW;AAAA;AAAA,MAEf;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA,IACF;AAEA,UAAM,UAAuB,CAAC;AAG9B,UAAM,aAAa,mDAAmD,KAAK,OAAO;AAClF,QAAI,WAAY,QAAO,CAAC;AAExB,eAAW,WAAW,UAAU;AAC9B,cAAQ;AAAA,QACN,GAAG;AAAA,UAAY;AAAA,UAAS;AAAA,UAAS;AAAA,UAAc;AAAA,UAAU,MACvD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAEA,IAAM,mBAA+B;AAAA,EACnC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AAEvB,QAAI,kCAAkC,KAAK,QAAQ,EAAG,QAAO,CAAC;AAC9D,QAAI,qDAAqD,KAAK,OAAO,EAAG,QAAO,CAAC;AAEhF,QAAI,wEAAwE,KAAK,OAAO,EAAG,QAAO,CAAC;AACnG,UAAM,WAAW;AAAA;AAAA,MAEf;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA,IACF;AAEA,UAAM,UAAuB,CAAC;AAC9B,eAAW,WAAW,UAAU;AAC9B,cAAQ;AAAA,QACN,GAAG;AAAA,UAAY;AAAA,UAAS;AAAA,UAAS;AAAA,UAAkB;AAAA,UAAU,MAC3D;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAEA,IAAM,iBAA6B;AAAA,EACjC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AAEvB,UAAM,cAAc,sCAAsC,KAAK,QAAQ,KACnD,SAAS,SAAS,YAAY;AAClD,QAAI,CAAC,YAAa,QAAO,CAAC;AAG1B,UAAM,WAAW,2DAA2D,KAAK,OAAO;AACxF,QAAI,CAAC,SAAU,QAAO,CAAC;AAGvB,UAAM,eAAe,+EAA+E,KAAK,OAAO;AAChH,QAAI,aAAc,QAAO,CAAC;AAE1B,WAAO,CAAC;AAAA,MACN,MAAM;AAAA,MACN,OAAO,eAAe;AAAA,MACtB,UAAU;AAAA,MACV,UAAU;AAAA,MACV,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,WAAW,SAAS,CAAC;AAAA,MAC9B,KAAK;AAAA,IACP,CAAC;AAAA,EACH;AACF;AAEA,IAAM,eAA2B;AAAA,EAC/B,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,WAAW,QAAQ,EAAG,QAAO,CAAC;AAClC,UAAM,WAAW;AAAA,MACf;AAAA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,UAAM,UAAuB,CAAC;AAC9B,eAAW,WAAW,UAAU;AAC9B,cAAQ;AAAA,QACN,GAAG;AAAA,UAAY;AAAA,UAAS;AAAA,UAAS;AAAA,UAAc;AAAA,UAAU,MACvD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAEA,IAAM,iBAA6B;AAAA,EACjC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AAEvB,QAAI,CAAC,SAAS,MAAM,yBAAyB,EAAG,QAAO,CAAC;AAExD,UAAM,UAAuB,CAAC;AAG9B,UAAM,eAAe;AAAA,MACnB;AAAA,MACA;AAAA,IACF;AAEA,eAAW,WAAW,cAAc;AAElC,YAAM,iBAAiB,wDAAwD,KAAK,OAAO;AAC3F,UAAI,eAAgB;AAEpB,cAAQ;AAAA,QACN,GAAG;AAAA,UAAY;AAAA,UAAS;AAAA,UAAS;AAAA,UAAgB;AAAA,UAAU,MACzD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,mBAA+B;AAAA,EACnC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,MAAM,OAAO,KAAK,CAAC,SAAS,MAAM,cAAc,EAAG,QAAO,CAAC;AACzE,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,IACF;AACA,UAAM,UAAuB,CAAC;AAC9B,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAkB;AAAA,QAAU,MAClE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,uBAAmC;AAAA,EACvC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,YAAY,KAAK,OAAO,EAAG,QAAO,CAAC;AACxC,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,IACF;AACA,UAAM,UAAuB,CAAC;AAC9B,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAsB;AAAA,QAAU,MACtE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,oBAAgC;AAAA,EACpC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,YAAY,KAAK,OAAO,EAAG,QAAO,CAAC;AACxC,QAAI,CAAC,QAAQ,KAAK,OAAO,EAAG,QAAO,CAAC;AACpC,QAAI,gBAAgB,KAAK,OAAO,EAAG,QAAO,CAAC;AAC3C,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,IACF;AACA,UAAM,UAAuB,CAAC;AAC9B,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAmB;AAAA,QAAU,MACnE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,mBAA+B;AAAA,EACnC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,SAAS,YAAY,EAAG,QAAO,CAAC;AAC9C,QAAI,SAAS,KAAK,OAAO,EAAG,QAAO,CAAC;AACpC,WAAO,CAAC;AAAA,MACN,MAAM;AAAA,MAAS,OAAO,iBAAiB;AAAA,MAAO,UAAU;AAAA,MAAiB,UAAU;AAAA,MACnF,MAAM;AAAA,MAAU,MAAM;AAAA,MAAG,SAAS,WAAW,SAAS,CAAC;AAAA,MACvD,KAAK;AAAA,IACP,CAAC;AAAA,EACH;AACF;AAMA,IAAM,YAAwB;AAAA,EAC5B,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,SAAS,SAAS,cAAc,KAAK,SAAS,SAAS,OAAO,EAAG,QAAO,CAAC;AAC7E,QAAI,SAAS,MAAM,0DAA0D,EAAG,QAAO,CAAC;AACxF,QAAI,WAAW,QAAQ,EAAG,QAAO,CAAC;AAElC,QAAI,SAAS,MAAM,8CAA8C,KAAK,4BAA4B,KAAK,OAAO,EAAG,QAAO,CAAC;AACzH,UAAM,WAAW;AAAA;AAAA,MAEf;AAAA,MACA;AAAA,IACF;AAEA,UAAM,kBAAkB,kCAAkC,KAAK,OAAO;AACtE,QAAI,mBAAmB,CAAC,2DAA2D,KAAK,OAAO,EAAG,QAAO,CAAC;AAC1G,UAAM,UAAuB,CAAC;AAC9B,eAAW,KAAK,UAAU;AACxB,YAAM,aAAa;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAW;AAAA,QAAU,MAC9D;AAAA,MACF;AAEA,iBAAWA,OAAM,YAAY;AAC3B,cAAM,YAAY,QAAQ,YAAY,MAAM,QAAQ,MAAM,IAAI,EAAE,MAAM,GAAGA,IAAG,OAAO,CAAC,EAAE,KAAK,IAAI,EAAE,MAAM,IAAI;AAC3G,cAAM,UAAU,QAAQ,QAAQ,MAAM,YAAY,CAAC;AACnD,cAAM,WAAW,QAAQ,UAAU,WAAW,YAAY,KAAK,QAAQ,SAAS,OAAO;AACvF,YAAI,sBAAsB,KAAK,QAAQ,EAAG;AAE1C,YAAI,wCAAwC,KAAK,QAAQ,EAAG;AAC5D,gBAAQ,KAAKA,GAAE;AAAA,MACjB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,sBAAkC;AAAA,EACtC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,UAAuB,CAAC;AAC9B,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAqB;AAAA,QAAU,MACrE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,kBAA8B;AAAA,EAClC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,WAAW,QAAQ,EAAG,QAAO,CAAC;AAClC,QAAI,CAAC,UAAU,KAAK,OAAO,EAAG,QAAO,CAAC;AACtC,UAAM,mBAAmB;AACzB,QAAI,CAAC,iBAAiB,KAAK,OAAO,EAAG,QAAO,CAAC;AAC7C,UAAM,cAAc,gCAAgC,KAAK,OAAO;AAChE,UAAM,YAAY,gCAAgC,KAAK,OAAO;AAC9D,UAAM,cAAc,yBAAyB,KAAK,OAAO;AACzD,UAAM,UAAuB,CAAC;AAC9B,QAAI,CAAC,eAAe,CAAC,aAAa,CAAC,aAAa;AAC9C,YAAM,UAAoB,CAAC;AAC3B,UAAI,CAAC,YAAa,SAAQ,KAAK,UAAU;AACzC,UAAI,CAAC,UAAW,SAAQ,KAAK,QAAQ;AACrC,UAAI,CAAC,YAAa,SAAQ,KAAK,UAAU;AACzC,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAA0D;AAAA,QAAiB;AAAA,QAAU,MACxH,6BAA6B,QAAQ,KAAK,IAAI,CAAC;AAAA,MACjD,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,oBAAgC;AAAA,EACpC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,UAAM,eAAe,SAAS,MAAM,yBAAyB,KAAK,qBAAqB,KAAK,OAAO;AACnG,UAAM,YAAY,SAAS,MAAM,OAAO;AACxC,QAAI,CAAC,gBAAgB,CAAC,UAAW,QAAO,CAAC;AACzC,UAAM,WAAqB,CAAC;AAC5B,QAAI,cAAc;AAChB,eAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,QAAI,WAAW;AACb,eAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,UAAM,UAAuB,CAAC;AAC9B,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAmB;AAAA,QAAU,MACnE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,yBAAqC;AAAA,EACzC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,WAAW,QAAQ,EAAG,QAAO,CAAC;AAClC,QAAI,CAAC,iBAAiB,KAAK,OAAO,EAAG,QAAO,CAAC;AAC7C,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAwB;AAAA,QAAU,CAAC,MACzE,OAAO,EAAE,CAAC,EAAE,MAAM,GAAG,EAAE,CAAC,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,SAAS,MAAM,IAAI,UAAU,MAAM;AAAA,MAC/E,CAAC;AAAA,IACH;AAEA,QAAI,4BAA4B,KAAK,OAAO,GAAG;AAC7C,UAAI,CAAC,eAAe,KAAK,OAAO,GAAG;AACjC,gBAAQ,KAAK,GAAG;AAAA,UAAY;AAAA,UAAS;AAAA,UAA6B,EAAE,GAAG,wBAAwB,OAAO,8CAA8C;AAAA,UAAG;AAAA,UAAU,MAC/J;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,aAAyB;AAAA,EAC7B,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AAEvB,QAAI,SAAS,MAAM,eAAe,GAAG;AACnC,UAAI,CAAC,2BAA2B,KAAK,OAAO,GAAG;AAC7C,eAAO,CAAC;AAAA,UACN,MAAM;AAAA,UAAS,OAAO,WAAW;AAAA,UAAO,UAAU;AAAA,UAAiB,UAAU;AAAA,UAC7E,MAAM;AAAA,UAAU,MAAM;AAAA,UAAG,SAAS,WAAW,SAAS,CAAC;AAAA,UACvD,KAAK;AAAA,QACP,CAAC;AAAA,MACH;AAAA,IACF;AAGA,WAAO,CAAC;AAAA,EACV;AACF;AAMA,IAAM,mBAA+B;AAAA,EACnC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,+BAA+B,KAAK,OAAO,EAAG,QAAO,CAAC;AAC3D,UAAM,UAAuB,CAAC;AAE9B,UAAM,aAAa,oFAAoF,KAAK,OAAO;AACnH,QAAI,CAAC,WAAY,QAAO,CAAC;AACzB,UAAM,oBAAoB,iJAAiJ,KAAK,OAAO;AACvL,QAAI,CAAC,mBAAmB;AACtB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAqG;AAAA,QAAkB;AAAA,QAAU,MACpK;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,wBAAoC;AAAA,EACxC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,WAAW,QAAQ,EAAG,QAAO,CAAC;AAElC,QAAI,uBAAuB,KAAK,OAAO,EAAG,QAAO,CAAC;AAElD,QAAI,SAAS,MAAM,yBAAyB,KAAK,CAAC,wCAAwC,KAAK,OAAO,EAAG,QAAO,CAAC;AAEjH,UAAM,eAAe,wDAAwD,KAAK,OAAO;AACzF,QAAI,aAAc,QAAO,CAAC;AAE1B,QAAI,CAAC,qGAAqG,KAAK,OAAO,EAAG,QAAO,CAAC;AACjI,UAAM,UAAuB,CAAC;AAC9B,UAAM,oBAAoB;AAAA,MACxB;AAAA,MACA;AAAA,IACF;AACA,eAAW,KAAK,mBAAmB;AACjC,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAuB;AAAA,QAAU,MACvE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,qBAAiC;AAAA,EACrC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,UAAM,UAAuB,CAAC;AAE9B,UAAM,uBAAuB;AAAA,MAC3B;AAAA,MACA;AAAA,IACF;AACA,UAAM,gBAAgB,wFAAwF,KAAK,OAAO;AAC1H,QAAI,cAAe,QAAO,CAAC;AAE3B,UAAM,iBAAiB,uGAAuG,KAAK,OAAO;AAC1I,QAAI,gBAAgB;AAClB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAA0D;AAAA,QAAoB;AAAA,QAAU,MAC3H;AAAA,MACF,CAAC;AAAA,IACH;AACA,eAAW,KAAK,sBAAsB;AACpC,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAoB;AAAA,QAAU,MACpE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,wBAAoC;AAAA,EACxC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,oCAAoC,KAAK,QAAQ,KAAK,CAAC,iDAAiD,KAAK,OAAO,EAAG,QAAO,CAAC;AAEpI,UAAM,cAAc,kFAAkF,KAAK,OAAO,KAC9F,oCAAoC,KAAK,OAAO;AACpE,QAAI,CAAC,YAAa,QAAO,CAAC;AAC1B,UAAM,eAAe,uGAAuG,KAAK,OAAO;AACxI,QAAI,aAAc,QAAO,CAAC;AAC1B,WAAO;AAAA,MAAY;AAAA,MAAS;AAAA,MAAqC;AAAA,MAAuB;AAAA,MAAU,MAChG;AAAA,IACF;AAAA,EACF;AACF;AAMA,IAAM,uBAAmC;AAAA,EACvC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,UAAM,UAAuB,CAAC;AAE9B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,kBAAkB,iEAAiE,KAAK,OAAO;AACrG,QAAI,gBAAiB,QAAO,CAAC;AAC7B,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAsB;AAAA,QAAU,MACtE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,iCAA6C;AAAA,EACjD,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,0BAA0B,KAAK,OAAO,EAAG,QAAO,CAAC;AACtD,QAAI,CAAC,cAAc,KAAK,QAAQ,EAAG,QAAO,CAAC;AAC3C,UAAM,cAAc,2EAA2E,KAAK,OAAO;AAC3G,QAAI,YAAa,QAAO,CAAC;AACzB,QAAI,uBAAuB,KAAK,OAAO,GAAG;AACxC,aAAO;AAAA,QAAY;AAAA,QAAS;AAAA,QAA6B;AAAA,QAAgC;AAAA,QAAU,MACjG;AAAA,MACF;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV;AACF;AAMA,IAAM,sBAAkC;AAAA,EACtC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,MAAM,eAAe,EAAG,QAAO,CAAC;AAC9C,UAAM,UAAuB,CAAC;AAC9B,QAAI,CAAC,0BAA0B,KAAK,OAAO,KAAK,CAAC,qBAAqB,KAAK,OAAO,GAAG;AACnF,cAAQ,KAAK;AAAA,QACX,MAAM;AAAA,QAAS,OAAO;AAAA,QAAyC,UAAU;AAAA,QACzE,UAAU;AAAA,QAAiB,MAAM;AAAA,QAAU,MAAM;AAAA,QAAG,SAAS,WAAW,SAAS,CAAC;AAAA,QAClF,KAAK;AAAA,MACP,CAAC;AAAA,IACH;AACA,QAAI,CAAC,YAAY,KAAK,OAAO,GAAG;AAC9B,cAAQ,KAAK;AAAA,QACX,MAAM;AAAA,QAAS,OAAO;AAAA,QAA2B,UAAU;AAAA,QAC3D,UAAU;AAAA,QAAiB,MAAM;AAAA,QAAU,MAAM;AAAA,QAAG,SAAS,WAAW,SAAS,CAAC;AAAA,QAClF,KAAK;AAAA,MACP,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,uBAAmC;AAAA,EACvC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,UAAM,UAAuB,CAAC;AAE9B,UAAM,iBAAiB;AAAA,MACrB;AAAA,MACA;AAAA,IACF;AACA,UAAM,gBAAgB,sFAAsF,KAAK,OAAO;AACxH,QAAI,cAAe,QAAO,CAAC;AAE3B,QAAI,oDAAoD,KAAK,OAAO,KAAK,iCAAiC,KAAK,OAAO,GAAG;AACvH,YAAM,qBAAqB,gFAAgF,KAAK,OAAO;AACvH,UAAI,CAAC,sBAAsB,uCAAuC,KAAK,OAAO,GAAG;AAC/E,gBAAQ,KAAK,GAAG;AAAA,UAAY;AAAA,UAAS;AAAA,UAAsD;AAAA,UAAsB;AAAA,UAAU,MACzH;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AACA,eAAW,KAAK,gBAAgB;AAC9B,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAsB;AAAA,QAAU,MACtE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,uBAAmC;AAAA,EACvC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,UAAM,UAAuB,CAAC;AAE9B,QAAI,6CAA6C,KAAK,OAAO,GAAG;AAC9D,UAAI,CAAC,2CAA2C,KAAK,OAAO,GAAG;AAC7D,gBAAQ,KAAK,GAAG;AAAA,UAAY;AAAA,UAAS;AAAA,UAA8C;AAAA,UAAsB;AAAA,UAAU,MACjH;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAEA,QAAI,0BAA0B,KAAK,OAAO,KAAK,qBAAqB,KAAK,OAAO,GAAG;AACjF,YAAM,eAAe,gFAAgF,KAAK,OAAO;AACjH,UAAI,CAAC,cAAc;AACjB,gBAAQ,KAAK,GAAG;AAAA,UAAY;AAAA,UAAS;AAAA,UAA2B;AAAA,UAAsB;AAAA,UAAU,MAC9F;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,0BAAsC;AAAA,EAC1C,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA;AAAA,MAEf;AAAA,MACA;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA,IACF;AACA,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAyB;AAAA,QAAU,MACzE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,qBAAiC;AAAA,EACrC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,SAAS,SAAS,UAAU,KAAK,SAAS,SAAS,WAAW,KAAK,SAAS,SAAS,MAAM,EAAG,QAAO,CAAC;AAC1G,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,UAAuB,CAAC;AAC9B,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAoB;AAAA,QAAU,MACpE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,eAA2B;AAAA,EAC/B,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,SAAS,SAAS,UAAU,KAAK,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,QAAQ,EAAG,QAAO,CAAC;AACvG,QAAI,SAAS,MAAM,aAAa,EAAG,QAAO,CAAC;AAC3C,UAAM,UAAuB,CAAC;AAE9B,QAAI,+BAA+B,KAAK,OAAO,KAAK,CAAC,iCAAiC,KAAK,OAAO,EAAG,QAAO,CAAC;AAE7G,UAAM,cAAc;AACpB,UAAM,aAAa;AAAA,MAAY;AAAA,MAAS;AAAA,MAAa;AAAA,MAAc;AAAA,MAAU,MAC3E;AAAA,IACF;AAEA,eAAWA,OAAM,YAAY;AAC3B,YAAM,YAAY,QAAQ,YAAY,MAAM,QAAQ,MAAM,IAAI,EAAE,MAAM,GAAGA,IAAG,OAAO,CAAC,EAAE,KAAK,IAAI,EAAE,MAAM,IAAI;AAC3G,YAAM,UAAU,QAAQ,QAAQ,MAAM,YAAY,CAAC;AACnD,YAAM,YAAY,QAAQ,UAAU,WAAW,YAAY,KAAK,QAAQ,SAAS,OAAO;AACxF,UAAI,wCAAwC,KAAK,SAAS,EAAG;AAC7D,cAAQ,KAAKA,GAAE;AAAA,IACjB;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,mBAA+B;AAAA,EACnC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,UAAU,KAAK,SAAS,SAAS,cAAc,EAAG,QAAO,CAAC;AAC7G,QAAI,SAAS,MAAM,qBAAqB,EAAG,QAAO,CAAC;AACnD,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA;AAAA,MAEf;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,IACF;AACA,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAkB;AAAA,QAAU,MAClE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,qBAAiC;AAAA,EACrC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,WAAW,QAAQ,EAAG,QAAO,CAAC;AAElC,QAAI,CAAC,0BAA0B,KAAK,OAAO,EAAG,QAAO,CAAC;AACtD,UAAM,UAAuB,CAAC;AAE9B,UAAM,kBAAkB;AACxB,UAAM,aAAa;AAAA,MAAY;AAAA,MAAS;AAAA,MAAiB;AAAA,MAAoB;AAAA,MAAU,MACrF;AAAA,IACF;AAEA,UAAM,sBAAsB;AAC5B,eAAWA,OAAM,YAAY;AAC3B,YAAM,WAAW,QAAQ,MAAM,IAAI,EAAEA,IAAG,OAAO,CAAC,KAAK;AACrD,UAAI,oBAAoB,KAAK,QAAQ,EAAG;AACxC,cAAQ,KAAKA,GAAE;AAAA,IACjB;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,qBAAiC;AAAA,EACrC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA;AAAA,MAEf;AAAA,MACA;AAAA,IACF;AACA,UAAM,gBAAgB,6GAA6G,KAAK,OAAO;AAC/I,QAAI,cAAe,QAAO,CAAC;AAC3B,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAoB;AAAA,QAAU,MACpE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,uBAAmC;AAAA,EACvC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AAEvB,UAAM,WAAW,SAAS,MAAM,GAAG,EAAE,IAAI,KAAK;AAC9C,QAAI,CAAC,oBAAoB,KAAK,QAAQ,EAAG,QAAO,CAAC;AAEjD,QAAI,SAAS,MAAM,OAAO,EAAG,QAAO,CAAC;AAErC,QAAI,CAAC,SAAS,KAAK,OAAO,EAAG,QAAO,CAAC;AAErC,QAAI,+DAA+D,KAAK,OAAO,EAAG,QAAO,CAAC;AAC1F,QAAI,WAAW,KAAK,QAAQ,KAAK,CAAC,wBAAwB,KAAK,OAAO,EAAG,QAAO,CAAC;AAEjF,QAAI,CAAC,qDAAqD,KAAK,OAAO,EAAG,QAAO,CAAC;AACjF,QAAI,CAAC,mCAAmC,KAAK,OAAO,EAAG,QAAO,CAAC;AAC/D,UAAM,mBAAmB,2EAA2E,KAAK,OAAO;AAChH,QAAI,iBAAkB,QAAO,CAAC;AAC9B,QAAI,+BAA+B,KAAK,OAAO,GAAG;AAChD,aAAO,CAAC;AAAA,QACN,MAAM;AAAA,QAAS,OAAO,qBAAqB;AAAA,QAAO,UAAU;AAAA,QAAmB,UAAU;AAAA,QACzF,MAAM;AAAA,QAAU,MAAM;AAAA,QAAG,SAAS,WAAW,SAAS,CAAC;AAAA,QACvD,KAAK;AAAA,MACP,CAAC;AAAA,IACH;AACA,WAAO,CAAC;AAAA,EACV;AACF;AAMA,IAAM,qBAAiC;AAAA,EACrC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,UAAM,YAAY,4DAA4D,KAAK,QAAQ;AAC3F,QAAI,CAAC,UAAW,QAAO,CAAC;AACxB,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA;AAAA,MAEf;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,IACF;AACA,UAAM,cAAc,wEAAwE,KAAK,OAAO;AACxG,QAAI,YAAa,QAAO,CAAC;AACzB,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAoB;AAAA,QAAU,MACpE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,qBAAiC;AAAA,EACrC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,6CAA6C,KAAK,OAAO,EAAG,QAAO,CAAC;AACzE,UAAM,UAAuB,CAAC;AAE9B,UAAM,cAAc,sEAAsE,KAAK,OAAO;AACtG,UAAM,eAAe,iEAAiE,KAAK,OAAO;AAClG,QAAI,eAAe,CAAC,cAAc;AAChC,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAqC;AAAA,QAAoB;AAAA,QAAU,MACtG;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,kBAA8B;AAAA,EAClC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AAEvB,QAAI,CAAC,SAAS,SAAS,YAAY,EAAG,QAAO,CAAC;AAC9C,UAAM,cAAc,iDAAiD,KAAK,OAAO;AACjF,QAAI,aAAa;AACf,aAAO;AAAA,QAAY;AAAA,QAAS;AAAA,QAAuD;AAAA,QAAiB;AAAA,QAAU,MAC5G;AAAA,MACF;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV;AACF;AAMA,IAAM,gBAA4B;AAAA,EAChC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AAEvB,QAAI,CAAC,SAAS,MAAM,mFAAmF,EAAG,QAAO,CAAC;AAElH,QAAI,uDAAuD,KAAK,OAAO,GAAG;AACxE,YAAM,YAAY,yBAAyB,KAAK,OAAO;AACvD,UAAI,CAAC,WAAW;AACd,eAAO;AAAA,UAAY;AAAA,UAAS;AAAA,UAAsD;AAAA,UAAe;AAAA,UAAU,MACzG;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV;AACF;AAMA,IAAM,oBAAgC;AAAA,EACpC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,WAAW,QAAQ,EAAG,QAAO,CAAC;AAElC,UAAM,eAAe,oEAAoE,KAAK,QAAQ;AACtG,QAAI,CAAC,aAAc,QAAO,CAAC;AAC3B,UAAM,UAAuB,CAAC;AAE9B,UAAM,WAAW;AAAA,MACf;AAAA,IACF;AACA,UAAM,gBAAgB,6IAA6I,KAAK,OAAO;AAC/K,QAAI,cAAe,QAAO,CAAC;AAC3B,eAAW,KAAK,UAAU;AACxB,YAAM,aAAa;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAmB;AAAA,QAAU,MACtE;AAAA,MACF;AAEA,iBAAWA,OAAM,YAAY;AAC3B,cAAM,WAAW,QAAQ,MAAM,IAAI,EAAEA,IAAG,OAAO,CAAC,KAAK;AACrD,cAAM,WAAW,SAAS,MAAM,2DAA2D;AAC3F,YAAI,UAAU;AACZ,gBAAM,UAAU,SAAS,CAAC;AAE1B,gBAAM,WAAW,IAAI,OAAO,YAAY,OAAO,4BAA4B,GAAG;AAC9E,cAAI,SAAS,KAAK,OAAO,EAAG;AAAA,QAC9B;AACA,gBAAQ,KAAKA,GAAE;AAAA,MACjB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,iBAA6B;AAAA,EACjC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,UAAM,YAAY,yDAAyD,KAAK,QAAQ;AACxF,QAAI,CAAC,UAAW,QAAO,CAAC;AACxB,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA;AAAA,MAEf;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA,IACF;AACA,UAAM,kBAAkB,uEAAuE,KAAK,OAAO;AAC3G,QAAI,gBAAiB,QAAO,CAAC;AAC7B,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAgB;AAAA,QAAU,MAChE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,eAA2B;AAAA,EAC/B,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,MAAM,EAAG,QAAO,CAAC;AACpE,UAAM,UAAuB,CAAC;AAE9B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,IACF;AACA,UAAM,gBAAgB,+DAA+D,KAAK,OAAO;AACjG,QAAI,cAAe,QAAO,CAAC;AAC3B,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAc;AAAA,QAAU,MAC9D;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,eAA2B;AAAA,EAC/B,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,MAAM,EAAG,QAAO,CAAC;AACpE,UAAM,eAAe,oEAAoE,KAAK,QAAQ;AACtG,QAAI,CAAC,aAAc,QAAO,CAAC;AAC3B,UAAM,UAAuB,CAAC;AAE9B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,IACF;AACA,UAAM,kBAAkB,gDAAgD,KAAK,OAAO;AACpF,QAAI,gBAAiB,QAAO,CAAC;AAC7B,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAc;AAAA,QAAU,MAC9D;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,2BAAuC;AAAA,EAC3C,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,WAAW,QAAQ,EAAG,QAAO,CAAC;AAClC,QAAI,CAAC,2BAA2B,KAAK,OAAO,EAAG,QAAO,CAAC;AACvD,QAAI,CAAC,gGAAgG,KAAK,OAAO,KAC7G,CAAC,wCAAwC,KAAK,QAAQ,EAAG,QAAO,CAAC;AAErE,UAAM,gBAAgB,iOAAiO,KAAK,OAAO;AACnQ,QAAI,cAAe,QAAO,CAAC;AAC3B,UAAM,sBAAsB,oEAAoE,KAAK,OAAO;AAC5G,QAAI,CAAC,oBAAqB,QAAO,CAAC;AAClC,UAAM,aAAa;AAAA,MAAY;AAAA,MAAS;AAAA,MAAsE;AAAA,MAA0B;AAAA,MAAU,MAChJ;AAAA,IACF;AAEA,UAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,UAAM,oBAAoB;AAC1B,WAAO,WAAW,OAAO,CAACA,QAAO;AAC/B,YAAM,QAAQ,KAAK,IAAI,GAAGA,IAAG,OAAO,IAAI,EAAE;AAC1C,YAAM,MAAM,KAAK,IAAI,MAAM,QAAQA,IAAG,OAAO,IAAI,EAAE;AACnD,YAAM,SAAS,MAAM,MAAM,OAAO,GAAG,EAAE,KAAK,IAAI;AAChD,aAAO,CAAC,kBAAkB,KAAK,MAAM;AAAA,IACvC,CAAC;AAAA,EACH;AACF;AAMA,IAAM,kBAA8B;AAAA,EAClC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,yCAAyC,KAAK,OAAO,EAAG,QAAO,CAAC;AACrE,QAAI,CAAC,WAAW,KAAK,OAAO,EAAG,QAAO,CAAC;AACvC,UAAM,gBAAgB,uFAAuF,KAAK,OAAO;AACzH,QAAI,cAAe,QAAO,CAAC;AAC3B,UAAM,WAAW,8CAA8C,KAAK,OAAO;AAC3E,QAAI,CAAC,SAAU,QAAO,CAAC;AACvB,WAAO;AAAA,MAAY;AAAA,MAAS;AAAA,MAAgD;AAAA,MAAiB;AAAA,MAAU,MACrG;AAAA,IACF;AAAA,EACF;AACF;AAMA,IAAM,oBAAgC;AAAA,EACpC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,UAAM,cAAc,iCAAiC,KAAK,QAAQ,KAAK,yDAAyD,KAAK,OAAO;AAC5I,QAAI,CAAC,YAAa,QAAO,CAAC;AAC1B,QAAI,CAAC,2BAA2B,KAAK,OAAO,EAAG,QAAO,CAAC;AACvD,UAAM,gBAAgB,sIAAsI,KAAK,OAAO;AACxK,QAAI,cAAe,QAAO,CAAC;AAC3B,WAAO;AAAA,MAAY;AAAA,MAAS;AAAA,MAAqD;AAAA,MAAmB;AAAA,MAAU,MAC5G;AAAA,IACF;AAAA,EACF;AACF;AAMA,IAAM,iBAA6B;AAAA,EACjC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,mEAAmE,KAAK,OAAO,EAAG,QAAO,CAAC;AAC/F,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA;AAAA,MAEf;AAAA,MACA;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA,IACF;AACA,UAAM,kBAAkB,uFAAuF,KAAK,OAAO;AAC3H,QAAI,gBAAiB,QAAO,CAAC;AAC7B,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAgB;AAAA,QAAU,MAChE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,uBAAmC;AAAA,EACvC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,SAAS,SAAS,UAAU,KAAK,SAAS,SAAS,WAAW,EAAG,QAAO,CAAC;AAC7E,QAAI,CAAC,SAAS,MAAM,mEAAmE,KAAK,CAAC,SAAS,MAAM,+BAA+B,EAAG,QAAO,CAAC;AACtJ,QAAI,SAAS,MAAM,OAAO,EAAG,QAAO,CAAC;AACrC,UAAM,WAAW;AAAA;AAAA,MAEf;AAAA;AAAA,MAEA;AAAA,IACF;AACA,UAAM,UAAuB,CAAC;AAC9B,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAsB;AAAA,QAAU,MACtE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,sBAAkC;AAAA,EACtC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,2FAA2F,KAAK,OAAO,EAAG,QAAO,CAAC;AACvH,QAAI,CAAC,uCAAuC,KAAK,OAAO,EAAG,QAAO,CAAC;AACnE,UAAM,UAAuB,CAAC;AAE9B,UAAM,cAAc;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,eAAW,KAAK,aAAa;AAC3B,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAqB;AAAA,QAAU,MACrE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,uBAAmC;AAAA,EACvC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,WAAW,KAAK,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ,EAAG,QAAO,CAAC;AACrE,UAAM,UAAuB,CAAC;AAE9B,QAAI,4BAA4B,KAAK,OAAO,GAAG;AAC7C,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAA8B;AAAA,QAAsB;AAAA,QAAU,MACjG;AAAA,MACF,CAAC;AAAA,IACH;AAEA,QAAI,mFAAmF,KAAK,OAAO,GAAG;AACpG,UAAI,CAAC,iBAAiB,KAAK,OAAO,GAAG;AACnC,gBAAQ,KAAK,GAAG;AAAA,UAAY;AAAA,UAAS;AAAA,UAAoD;AAAA,UAAsB;AAAA,UAAU,MACvH;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,0BAAsC;AAAA,EAC1C,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,sCAAsC,KAAK,QAAQ,EAAG,QAAO,CAAC;AACnE,QAAI,CAAC,gCAAgC,KAAK,OAAO,EAAG,QAAO,CAAC;AAC5D,UAAM,UAAuB,CAAC;AAE9B,QAAI,2BAA2B,KAAK,OAAO,GAAG;AAC5C,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAA4B;AAAA,QAAyB;AAAA,QAAU,MAClG;AAAA,MACF,CAAC;AAAA,IACH;AAEA,QAAI,8BAA8B,KAAK,OAAO,GAAG;AAC/C,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAA+B;AAAA,QAAyB;AAAA,QAAU,MACrG;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,uBAAmC;AAAA,EACvC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,MAAM,KAAK,SAAS,MAAM,aAAa,EAAG,QAAO,CAAC;AACrG,UAAM,UAAuB,CAAC;AAE9B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,IACF;AACA,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAsB;AAAA,QAAU,MACtE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,wBAAoC;AAAA,EACxC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,MAAM,2BAA2B,EAAG,QAAO,CAAC;AAC1D,QAAI,WAAW,QAAQ,EAAG,QAAO,CAAC;AAElC,QAAI,aAAa,KAAK,QAAQ,EAAG,QAAO,CAAC;AAEzC,QAAI,CAAC,wCAAwC,KAAK,OAAO,EAAG,QAAO,CAAC;AACpE,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,IACF;AACA,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAuB;AAAA,QAAU,MACvE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,oBAAgC;AAAA,EACpC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AAEvB,QAAI,CAAC,SAAS,MAAM,gDAAgD,EAAG,QAAO,CAAC;AAC/E,UAAM,UAAuB,CAAC;AAE9B,QAAI,oDAAoD,KAAK,OAAO,GAAG;AACrE,YAAM,cAAc,8CAA8C,KAAK,OAAO;AAC9E,UAAI,CAAC,aAAa;AAChB,gBAAQ,KAAK,GAAG;AAAA,UAAY;AAAA,UAAS;AAAA,UAAsD;AAAA,UAAmB;AAAA,UAAU,MACtH;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAEA,QAAI,kCAAkC,KAAK,OAAO,GAAG;AACnD,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAoC;AAAA,QAAmB;AAAA,QAAU,MACpG;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,eAA2B;AAAA,EAC/B,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AAEvB,QAAI,SAAS,MAAM,eAAe,GAAG;AACnC,UAAI,CAAC,mCAAmC,KAAK,OAAO,GAAG;AACrD,eAAO,CAAC;AAAA,UACN,MAAM;AAAA,UAAS,OAAO,aAAa;AAAA,UAAO,UAAU;AAAA,UAAmB,UAAU;AAAA,UACjF,MAAM;AAAA,UAAU,MAAM;AAAA,UAAG,SAAS,WAAW,SAAS,CAAC;AAAA,UACvD,KAAK;AAAA,QACP,CAAC;AAAA,MACH;AAAA,IACF;AAEA,QAAI,sCAAsC,KAAK,QAAQ,GAAG;AACxD,UAAI,gCAAgC,KAAK,OAAO,GAAG;AACjD,YAAI,CAAC,0CAA0C,KAAK,OAAO,GAAG;AAC5D,iBAAO;AAAA,YAAY;AAAA,YAAS;AAAA,YAAuC;AAAA,YAAc;AAAA,YAAU,MACzF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV;AACF;AAMA,IAAM,sBAAkC;AAAA,EACtC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,MAAM,2BAA2B,KAAK,CAAC,SAAS,MAAM,iCAAiC,EAAG,QAAO,CAAC;AAChH,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA;AAAA,MAEf;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,IACF;AACA,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAqB;AAAA,QAAU,MACrE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,kBAA8B;AAAA,EAClC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,MAAM,cAAc,EAAG,QAAO,CAAC;AAC7C,UAAM,UAAU,eAAe,KAAK,OAAO;AAC3C,QAAI,QAAS,QAAO,CAAC;AACrB,WAAO,CAAC;AAAA,MACN,MAAM;AAAA,MAAS,OAAO,gBAAgB;AAAA,MAAO,UAAU;AAAA,MAAiB,UAAU;AAAA,MAClF,MAAM;AAAA,MAAU,MAAM;AAAA,MAAG,SAAS,WAAW,SAAS,CAAC;AAAA,MACvD,KAAK;AAAA,IACP,CAAC;AAAA,EACH;AACF;AAMA,IAAM,qBAAiC;AAAA,EACrC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,MAAM,sCAAsC,EAAG,QAAO,CAAC;AACrE,UAAM,UAAuB,CAAC;AAE9B,UAAM,cAAc;AACpB,QAAI,YAAY,KAAK,OAAO,KAAK,CAAC,iBAAiB,KAAK,OAAO,GAAG;AAChE,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAiC;AAAA,QAAoB;AAAA,QAAU,MAClG;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,cAA0B;AAAA,EAC9B,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,MAAM,EAAG,QAAO,CAAC;AAEpE,QAAI,wBAAwB,KAAK,OAAO,EAAG,QAAO,CAAC;AACnD,UAAM,UAAuB,CAAC;AAE9B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAa;AAAA,QAAU,MAC7D;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,0BAAsC;AAAA,EAC1C,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAyB;AAAA,QAAU,MACzE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,yBAAqC;AAAA,EACzC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,SAAS,SAAS,UAAU,KAAK,SAAS,SAAS,WAAW,EAAG,QAAO,CAAC;AAC7E,QAAI,WAAW,QAAQ,EAAG,QAAO,CAAC;AAElC,QAAI,SAAS,MAAM,mCAAmC,EAAG,QAAO,CAAC;AAEjE,QAAI,CAAC,sDAAsD,KAAK,OAAO,EAAG,QAAO,CAAC;AAClF,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA;AAAA,MAEf;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA,IACF;AACA,eAAW,KAAK,UAAU;AACxB,YAAM,aAAa;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAwB;AAAA,QAAU,MAC3E;AAAA,MACF;AAEA,iBAAWA,OAAM,YAAY;AAC3B,cAAM,YAAY,QAAQ,YAAY,MAAM,QAAQ,MAAM,IAAI,EAAE,MAAM,GAAGA,IAAG,OAAO,CAAC,EAAE,KAAK,IAAI,EAAE,MAAM,IAAI;AAC3G,cAAM,UAAU,QAAQ,QAAQ,MAAM,YAAY,CAAC;AACnD,cAAM,WAAW,QAAQ,UAAU,WAAW,YAAY,KAAK,QAAQ,SAAS,OAAO;AACvF,YAAI,4EAA4E,KAAK,QAAQ,EAAG;AAChG,gBAAQ,KAAKA,GAAE;AAAA,MACjB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,qBAAiC;AAAA,EACrC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,MAAM,cAAc,EAAG,QAAO,CAAC;AAC7C,QAAI,CAAC,2BAA2B,KAAK,OAAO,EAAG,QAAO,CAAC;AACvD,UAAM,cAAc,mEAAmE,KAAK,OAAO;AACnG,QAAI,YAAa,QAAO,CAAC;AACzB,WAAO;AAAA,MAAY;AAAA,MAAS;AAAA,MAA0C;AAAA,MAAoB;AAAA,MAAU,MAClG;AAAA,IACF;AAAA,EACF;AACF;AAMA,IAAM,uBAAmC;AAAA,EACvC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,MAAM,gBAAgB,EAAG,QAAO,CAAC;AAC/C,QAAI,CAAC,sBAAsB,KAAK,OAAO,EAAG,QAAO,CAAC;AAClD,UAAM,UAAU,mFAAmF,KAAK,OAAO;AAC/G,QAAI,QAAS,QAAO,CAAC;AAErB,QAAI,6BAA6B,KAAK,OAAO,GAAG;AAC9C,aAAO;AAAA,QAAY;AAAA,QAAS;AAAA,QAAoC;AAAA,QAAsB;AAAA,QAAU,MAC9F;AAAA,MACF;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV;AACF;AAMA,IAAM,uBAAmC;AAAA,EACvC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,MAAM,yBAAyB,KAAK,CAAC,SAAS,MAAM,mCAAmC,EAAG,QAAO,CAAC;AAEhH,QAAI,gCAAgC,KAAK,QAAQ,EAAG,QAAO,CAAC;AAC5D,UAAM,UAAU,uHAAuH,KAAK,OAAO;AACnJ,QAAI,QAAS,QAAO,CAAC;AACrB,UAAM,aAAa,mFAAmF,KAAK,OAAO;AAClH,QAAI,YAAY;AACd,aAAO;AAAA,QAAY;AAAA,QAAS;AAAA,QAAmE;AAAA,QAAsB;AAAA,QAAU,MAC7H;AAAA,MACF;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV;AACF;AAMA,IAAM,wBAAoC;AAAA,EACxC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,MAAM,gBAAgB,EAAG,QAAO,CAAC;AAC/C,QAAI,CAAC,sBAAsB,KAAK,OAAO,EAAG,QAAO,CAAC;AAElD,UAAM,UAAU;AAChB,QAAI,QAAQ,KAAK,OAAO,GAAG;AACzB,aAAO;AAAA,QAAY;AAAA,QAAS;AAAA,QAA6C;AAAA,QAAuB;AAAA,QAAU,MACxG;AAAA,MACF;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV;AACF;AAMA,IAAM,mBAA+B;AAAA,EACnC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,oEAAoE,KAAK,OAAO,EAAG,QAAO,CAAC;AAChG,UAAM,UAAuB,CAAC;AAE9B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,gBAAgB,0FAA0F,KAAK,OAAO;AAC5H,QAAI,cAAe,QAAO,CAAC;AAC3B,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAkB;AAAA,QAAU,MAClE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,wBAAoC;AAAA,EACxC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,gBAAgB,KAAK,OAAO,EAAG,QAAO,CAAC;AAC5C,UAAM,WAAW;AAAA,MACf;AAAA,IACF;AACA,UAAM,UAAuB,CAAC;AAC9B,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAuB;AAAA,QAAU,MACvE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,qBAAiC;AAAA,EACrC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AAEvB,QAAI,CAAC,4CAA4C,KAAK,QAAQ,KAAK,CAAC,0BAA0B,KAAK,OAAO,EAAG,QAAO,CAAC;AACrH,QAAI,CAAC,oCAAoC,KAAK,OAAO,EAAG,QAAO,CAAC;AAEhE,QAAI,gDAAgD,KAAK,OAAO,GAAG;AACjE,YAAM,aAAa,8EAA8E,KAAK,OAAO;AAC7G,UAAI,CAAC,YAAY;AACf,eAAO;AAAA,UAAY;AAAA,UAAS;AAAA,UAAkD;AAAA,UAAoB;AAAA,UAAU,MAC1G;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV;AACF;AAMA,IAAM,oBAAgC;AAAA,EACpC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,MAAM,wBAAwB,EAAG,QAAO,CAAC;AACvD,QAAI,yCAAyC,KAAK,OAAO,GAAG;AAC1D,aAAO;AAAA,QAAY;AAAA,QAAS;AAAA,QAA2C;AAAA,QAAmB;AAAA,QAAU,MAClG;AAAA,MACF;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV;AACF;AAMA,IAAM,cAA0B;AAAA,EAC9B,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,MAAM,gBAAgB,KAAK,CAAC,SAAS,MAAM,gBAAgB,EAAG,QAAO,CAAC;AACpF,QAAI,4BAA4B,KAAK,OAAO,GAAG;AAC7C,YAAM,cAAc,qCAAqC,KAAK,OAAO;AACrE,UAAI,CAAC,aAAa;AAChB,eAAO;AAAA,UAAY;AAAA,UAAS;AAAA,UAA0B;AAAA,UAAa;AAAA,UAAU,MAC3E;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV;AACF;AAMA,IAAM,iBAA6B;AAAA,EACjC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,MAAM,OAAO,EAAG,QAAO,CAAC;AACtC,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,IACF;AACA,UAAM,SAAS,qCAAqC,KAAK,OAAO;AAChE,QAAI,OAAQ,QAAO,CAAC;AACpB,UAAM,UAAuB,CAAC;AAC9B,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAgB;AAAA,QAAU,MAChE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,wBAAoC;AAAA,EACxC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,MAAM,OAAO,EAAG,QAAO,CAAC;AACtC,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,UAAU,4DAA4D,KAAK,OAAO;AACxF,QAAI,QAAS,QAAO,CAAC;AACrB,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAuB;AAAA,QAAU,MACvE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,cAA0B;AAAA,EAC9B,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,MAAM,OAAO,EAAG,QAAO,CAAC;AACtC,UAAM,UAAuB,CAAC;AAC9B,QAAI,eAAe,KAAK,OAAO,GAAG;AAChC,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAiB;AAAA,QAAa;AAAA,QAAU,MAC3E;AAAA,MACF,CAAC;AAAA,IACH;AAEA,QAAI,qBAAqB,KAAK,OAAO,KAAK,CAAC,sBAAsB,KAAK,OAAO,KAAK,UAAU,KAAK,OAAO,GAAG;AACzG,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAmB;AAAA,QAAa;AAAA,QAAU,MAC7E;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,yBAAqC;AAAA,EACzC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,MAAM,uCAAuC,EAAG,QAAO,CAAC;AACtE,UAAM,UAAuB,CAAC;AAE9B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,IACF;AACA,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAwB;AAAA,QAAU,MACxE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,cAA0B;AAAA,EAC9B,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,MAAM,+EAA+E,EAAG,QAAO,CAAC;AAC9G,UAAM,UAAuB,CAAC;AAE9B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,IACF;AACA,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAa;AAAA,QAAU,MAC7D;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,iBAA6B;AAAA,EACjC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,MAAM,iEAAiE,EAAG,QAAO,CAAC;AAChG,UAAM,UAAuB,CAAC;AAC9B,QAAI,gEAAgE,KAAK,OAAO,GAAG;AACjF,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAkE;AAAA,QAAgB;AAAA,QAAU,MAC/H;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,gBAA4B;AAAA,EAChC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,MAAM,eAAe,KAAK,CAAC,iCAAiC,KAAK,OAAO,EAAG,QAAO,CAAC;AACjG,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAe;AAAA,QAAU,MAC/D;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAQO,SAAS,gBAAgB,OAAiE;AAC/F,QAAM,aAAqC,oBAAI,IAAI;AACnD,aAAW,EAAE,MAAM,QAAQ,KAAK,OAAO;AACrC,QAAI,KAAK,MAAM,eAAe,KAAK,mBAAmB,KAAK,OAAO,EAAG,YAAW,IAAI,SAAS;AAC7F,QAAI,2BAA2B,KAAK,OAAO,KAAK,KAAK,MAAM,uBAAuB,EAAG,YAAW,IAAI,cAAc;AAAA,aACzG,oBAAoB,KAAK,OAAO,KAAK,kBAAkB,KAAK,OAAO,EAAG,YAAW,IAAI,OAAO;AACrG,QAAI,sBAAsB,KAAK,OAAO,KAAK,8BAA8B,KAAK,OAAO,EAAG,YAAW,IAAI,SAAS;AAChH,QAAI,mBAAmB,KAAK,OAAO,EAAG,YAAW,IAAI,MAAM;AAC3D,QAAI,sBAAsB,KAAK,OAAO,EAAG,YAAW,IAAI,SAAS;AACjE,QAAI,uBAAuB,KAAK,OAAO,KAAK,KAAK,MAAM,WAAW,EAAG,YAAW,IAAI,UAAU;AAC9F,QAAI,KAAK,MAAM,eAAe,KAAK,iBAAiB,KAAK,OAAO,EAAG,YAAW,IAAI,QAAQ;AAC1F,QAAI,gBAAgB,KAAK,OAAO,KAAK,cAAc,KAAK,OAAO,EAAG,YAAW,IAAI,OAAO;AACxF,QAAI,kBAAkB,KAAK,OAAO,KAAK,KAAK,MAAM,cAAc,EAAG,YAAW,IAAI,KAAK;AACvF,QAAI,qBAAqB,KAAK,OAAO,KAAK,KAAK,MAAM,iBAAiB,EAAG,YAAW,IAAI,QAAQ;AAAA,EAClG;AACA,MAAI,WAAW,SAAS,EAAG,YAAW,IAAI,SAAS;AACnD,SAAO,CAAC,GAAG,UAAU;AACvB;AAcO,SAAS,eAAe,UAAqB,YAAiC;AACnF,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO,EAAE,OAAO,MAAM,OAAO,KAAK,SAAS,0CAA0C;AAAA,EACvF;AAGA,MAAI,aAAa;AACjB,aAAW,KAAK,UAAU;AACxB,YAAQ,EAAE,UAAU;AAAA,MAClB,KAAK;AAAY,sBAAc;AAAI;AAAA,MACnC,KAAK;AAAQ,sBAAc;AAAG;AAAA,MAC9B,KAAK;AAAU,sBAAc;AAAG;AAAA,MAChC,KAAK;AAAO,sBAAc;AAAG;AAAA,IAC/B;AAAA,EACF;AAGA,QAAM,aAAa,KAAK,IAAI,KAAK,KAAK,KAAK,IAAI,YAAY,CAAC,CAAC,IAAI,GAAG,EAAE;AACtE,QAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,MAAM,aAAa,UAAU,CAAC;AAEtE,MAAI;AACJ,MAAI;AAEJ,MAAI,SAAS,IAAI;AAAE,YAAQ;AAAM,cAAU;AAAA,EAAmD,WACrF,SAAS,IAAI;AAAE,YAAQ;AAAK,cAAU;AAAA,EAA8C,WACpF,SAAS,IAAI;AAAE,YAAQ;AAAK,cAAU;AAAA,EAAiD,WACvF,SAAS,IAAI;AAAE,YAAQ;AAAK,cAAU;AAAA,EAA4D,WAClG,SAAS,IAAI;AAAE,YAAQ;AAAK,cAAU;AAAA,EAAgE,OAC1G;AAAE,YAAQ;AAAK,cAAU;AAAA,EAA+E;AAE7G,SAAO,EAAE,OAAO,OAAO,KAAK,MAAM,KAAK,GAAG,QAAQ;AACpD;AAMA,IAAM,kBAA8B;AAAA,EAClC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,yBAAyB,KAAK,OAAO,EAAG,QAAO,CAAC;AACrD,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,IACF;AACA,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAiB;AAAA,QAAU,MACjE;AAAA,MACF,CAAC;AAAA,IACH;AAEA,QAAI,8CAA8C,KAAK,OAAO,KAAK,CAAC,cAAc,KAAK,OAAO,GAAG;AAC/F,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAqB;AAAA,QAAiB;AAAA,QAAU,MACnF;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,WAAuB;AAAA,EAC3B,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,MAAM,EAAG,QAAO,CAAC;AACpE,UAAM,UAAuB,CAAC;AAE9B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,IACF;AACA,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAU;AAAA,QAAU,MAC1D;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,mBAA+B;AAAA,EACnC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,+CAA+C,KAAK,OAAO,EAAG,QAAO,CAAC;AAC3E,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,gBAAgB,iGAAiG,KAAK,OAAO;AACnI,QAAI,cAAe,QAAO,CAAC;AAC3B,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAkB;AAAA,QAAU,MAClE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,OAAmB;AAAA,EACvB,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,MAAM,EAAG,QAAO,CAAC;AACpE,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAM;AAAA,QAAU,MACtD;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,sBAAkC;AAAA,EACtC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,MAAM,eAAe,EAAG,QAAO,CAAC;AAC9C,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,UAAU,uFAAuF,KAAK,OAAO;AACnH,QAAI,QAAS,QAAO,CAAC;AACrB,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAqB;AAAA,QAAU,MACrE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,aAAyB;AAAA,EAC7B,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,SAAS,MAAM,+BAA+B,EAAG,QAAO,CAAC;AAC9D,UAAM,UAAuB,CAAC;AAE9B,UAAM,gBAAgB;AACtB,QAAI;AACJ,UAAM,KAAK,IAAI,OAAO,cAAc,QAAQ,cAAc,KAAK;AAC/D,YAAQ,IAAI,GAAG,KAAK,OAAO,OAAO,MAAM;AACtC,UAAI,CAAC,EAAE,CAAC,EAAE,SAAS,WAAW,GAAG;AAC/B,cAAM,UAAU,QAAQ,UAAU,GAAG,EAAE,KAAK,EAAE,MAAM,IAAI,EAAE;AAC1D,gBAAQ,KAAK;AAAA,UACX,MAAM;AAAA,UAAS,OAAO,WAAW;AAAA,UAAO,UAAU;AAAA,UAAU,UAAU;AAAA,UACtE,MAAM;AAAA,UAAU,MAAM;AAAA,UAAS,SAAS,WAAW,SAAS,OAAO;AAAA,UACnE,KAAK;AAAA,QACP,CAAC;AAAA,MACH;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,qBAAiC;AAAA,EACrC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,qDAAqD,KAAK,QAAQ,EAAG,QAAO,CAAC;AAClF,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA,MACf;AAAA,IACF;AACA,UAAM,UAAU,wEAAwE,KAAK,OAAO;AACpG,QAAI,QAAS,QAAO,CAAC;AACrB,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAoB;AAAA,QAAU,MACpE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,oBAAgC;AAAA,EACpC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,MAAM,EAAG,QAAO,CAAC;AACpE,WAAO;AAAA,MAAY;AAAA,MAAS;AAAA,MAAwC;AAAA,MAAmB;AAAA,MAAU,MAC/F;AAAA,IACF;AAAA,EACF;AACF;AAMA,IAAM,cAA0B;AAAA,EAC9B,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,sCAAsC,KAAK,QAAQ,EAAG,QAAO,CAAC;AACnE,QAAI,CAAC,gCAAgC,KAAK,OAAO,EAAG,QAAO,CAAC;AAC5D,QAAI,yCAAyC,KAAK,OAAO,EAAG,QAAO,CAAC;AACpE,WAAO;AAAA,MAAY;AAAA,MAAS;AAAA,MAAuC;AAAA,MAAa;AAAA,MAAU,MACxF;AAAA,IACF;AAAA,EACF;AACF;AAMA,IAAM,qBAAiC;AAAA,EACrC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,MAAM,EAAG,QAAO,CAAC;AACpE,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,IACF;AACA,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAoB;AAAA,QAAU,MACpE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,4BAAwC;AAAA,EAC5C,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,yDAAyD,KAAK,OAAO,EAAG,QAAO,CAAC;AACrF,QAAI,CAAC,yDAAyD,KAAK,QAAQ,EAAG,QAAO,CAAC;AACtF,QAAI,2CAA2C,KAAK,OAAO,EAAG,QAAO,CAAC;AACtE,WAAO;AAAA,MAAY;AAAA,MAAS;AAAA,MAAyD;AAAA,MAA2B;AAAA,MAAU,MACxH;AAAA,IACF;AAAA,EACF;AACF;AAMA,IAAM,qBAAiC;AAAA,EACrC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,MAAM,EAAG,QAAO,CAAC;AACpE,UAAM,UAAuB,CAAC;AAC9B,QAAI,qDAAqD,KAAK,OAAO,KAAK,qBAAqB,KAAK,OAAO,GAAG;AAC5G,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAuD;AAAA,QAAoB;AAAA,QAAU,MACxH;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,gBAA4B;AAAA,EAChC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,MAAM,EAAG,QAAO,CAAC;AACpE,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAe;AAAA,QAAU,MAC/D;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,qBAAiC;AAAA,EACrC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,MAAM,EAAG,QAAO,CAAC;AACpE,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,IACF;AACA,UAAM,UAAU,2DAA2D,KAAK,OAAO;AACvF,QAAI,QAAS,QAAO,CAAC;AACrB,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAoB;AAAA,QAAU,MACpE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,sBAAkC;AAAA,EACtC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,mCAAmC,KAAK,OAAO,EAAG,QAAO,CAAC;AAC/D,QAAI,CAAC,yDAAyD,KAAK,QAAQ,EAAG,QAAO,CAAC;AACtF,UAAM,UAAuB,CAAC;AAE9B,QAAI,8EAA8E,KAAK,OAAO,GAAG;AAC/F,YAAM,gBAAgB,yFAAyF,KAAK,OAAO;AAC3H,UAAI,CAAC,eAAe;AAClB,gBAAQ,KAAK,GAAG;AAAA,UAAY;AAAA,UAAS;AAAA,UAA0C;AAAA,UAAqB;AAAA,UAAU,MAC5G;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,mBAA+B;AAAA,EACnC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,MAAM,EAAG,QAAO,CAAC;AACpE,UAAM,UAAuB,CAAC;AAC9B,UAAM,WAAW;AAAA;AAAA,MAEf;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,IACF;AACA,UAAM,UAAU,0DAA0D,KAAK,OAAO;AACtF,QAAI,QAAS,QAAO,CAAC;AACrB,eAAW,KAAK,UAAU;AACxB,cAAQ,KAAK,GAAG;AAAA,QAAY;AAAA,QAAS;AAAA,QAAG;AAAA,QAAkB;AAAA,QAAU,MAClE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,gBAA4B;AAAA,EAChC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,MAAM,EAAG,QAAO,CAAC;AACjG,QAAI,CAAC,UAAU,KAAK,OAAO,EAAG,QAAO,CAAC;AACtC,WAAO;AAAA,MAAY;AAAA,MAAS;AAAA,MAA6C;AAAA,MAAe;AAAA,MAAU,MAChG;AAAA,IACF;AAAA,EACF;AACF;AAMA,IAAM,eAA2B;AAAA,EAC/B,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM,SAAS,UAAU;AACvB,QAAI,CAAC,QAAQ,KAAK,OAAO,EAAG,QAAO,CAAC;AACpC,WAAO;AAAA,MAAY;AAAA,MAAS;AAAA,MAAwD;AAAA,MAAc;AAAA,MAAU,MAC1G;AAAA,IACF;AAAA,EACF;AACF;AAMO,IAAM,gBAAgE;AAAA,EAC3E,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,SAAS;AAAA,EAC1C,OAAO,EAAE,OAAO,YAAY,KAAK,SAAS;AAAA,EAC1C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,SAAS;AAAA,EAC1C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,WAAW;AAAA,EAC5C,OAAO,EAAE,OAAO,YAAY,KAAK,SAAS;AAAA,EAC1C,OAAO,EAAE,OAAO,YAAY,KAAK,SAAS;AAAA,EAC1C,OAAO,EAAE,OAAO,YAAY,KAAK,WAAW;AAAA,EAC5C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,SAAS;AAAA,EAC1C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,SAAS;AAAA,EAC1C,OAAO,EAAE,OAAO,YAAY,KAAK,SAAS;AAAA,EAC1C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,WAAW;AAAA,EAC5C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,WAAW;AAAA,EAC5C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C,OAAO,EAAE,OAAO,Y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","names":["resolve","join","chalk","readFileSync","join","rm","existsSync","join","resolve","execFile","readFile","mkdtemp","rm","existsSync","join","tmpdir","resolve","execFile","mkdtemp","join","tmpdir","existsSync","readFile","rm","lines","getSnippet","getSnippet","getSnippet","getSnippet","resolve","chalk","join","execFile","chalk","ora","chalk","ora","resolve","execFile","getStoredToken","chalk","execFile"]}
|