@guardcore/core 1.0.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/detection-engine/preprocessor.ts","../src/detection-engine/compiler.ts","../src/detection-engine/monitor.ts","../src/detection-engine/semantic.ts","../src/handlers/sus-patterns.ts"],"sourcesContent":["const ATTACK_INDICATORS = [\n /<script/i,\n /javascript:/i,\n /on\\w+=/i,\n /SELECT\\s+.{0,50}?\\s+FROM/i,\n /UNION\\s+SELECT/i,\n /\\.\\.\\//,\n /eval\\s*\\(/i,\n /exec\\s*\\(/i,\n /system\\s*\\(/i,\n /<\\?php/i,\n /<%%/,\n /\\{\\{/,\n /\\{%/,\n /<iframe/i,\n /<object/i,\n /<embed/i,\n /onerror\\s*=/i,\n /onload\\s*=/i,\n /\\$\\{/,\n /\\\\x[0-9a-fA-F]{2}/,\n /%[0-9a-fA-F]{2}/,\n];\n\nconst LOOKALIKES: Record<string, string> = {\n '\\u2044': '/',\n '\\uff0f': '/',\n '\\u29f8': '/',\n '\\u0130': 'I',\n '\\u0131': 'i',\n '\\u200b': '',\n '\\u200c': '',\n '\\u200d': '',\n '\\ufeff': '',\n '\\u00ad': '',\n '\\u034f': '',\n '\\u180e': '',\n '\\u2028': '\\n',\n '\\u2029': '\\n',\n '\\ue000': '',\n '\\ufff0': '',\n '\\u01c0': '|',\n '\\u037e': ';',\n '\\u2215': '/',\n '\\u2216': '\\\\',\n '\\uff1c': '<',\n '\\uff1e': '>',\n};\n\nconst CONTROL_CHARS_RE = /[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f]/g;\n\nexport class ContentPreprocessor {\n private readonly maxContentLength: number;\n private readonly preserveAttackPatterns: boolean;\n\n constructor(maxContentLength = 10000, preserveAttackPatterns = true) {\n this.maxContentLength = maxContentLength;\n this.preserveAttackPatterns = preserveAttackPatterns;\n }\n\n normalizeUnicode(content: string): string {\n let normalized = content.normalize('NFKC');\n for (const [char, replacement] of Object.entries(LOOKALIKES)) {\n normalized = normalized.replaceAll(char, replacement);\n }\n return normalized;\n }\n\n removeNullBytes(content: string): string {\n return content.replace(/\\x00/g, '').replace(CONTROL_CHARS_RE, '');\n }\n\n removeExcessiveWhitespace(content: string): string {\n return content.replace(/\\s+/g, ' ').trim();\n }\n\n decodeCommonEncodings(content: string): string {\n const maxIterations = 3;\n let current = content;\n\n for (let i = 0; i < maxIterations; i++) {\n const original = current;\n\n try {\n const decoded = decodeURIComponent(current);\n if (decoded !== current) current = decoded;\n } catch {\n // partial encoding, ignore\n }\n\n try {\n current = this.decodeHtmlEntities(current);\n } catch {\n /* v8 ignore next -- HTML entity decoding fallback; decodeHtmlEntities uses only string ops that cannot throw */\n }\n\n if (current === original) break;\n }\n\n return current;\n }\n\n private decodeHtmlEntities(content: string): string {\n const entityMap: Record<string, string> = {\n '&amp;': '&', '&lt;': '<', '&gt;': '>', '&quot;': '\"',\n '&#39;': \"'\", '&apos;': \"'\", '&#x27;': \"'\", '&#x2F;': '/',\n '&#47;': '/', '&nbsp;': ' ',\n };\n\n let result = content;\n for (const [entity, char] of Object.entries(entityMap)) {\n result = result.replaceAll(entity, char);\n }\n\n result = result.replace(/&#x([0-9a-fA-F]+);/g, (_, hex) =>\n String.fromCharCode(parseInt(hex, 16)),\n );\n\n result = result.replace(/&#(\\d+);/g, (_, dec) =>\n String.fromCharCode(parseInt(dec, 10)),\n );\n\n return result;\n }\n\n extractAttackRegions(content: string): Array<[number, number]> {\n const maxRegions = Math.min(100, Math.floor(this.maxContentLength / 100));\n const regions: Array<[number, number]> = [];\n\n for (const indicator of ATTACK_INDICATORS) {\n const regex = new RegExp(indicator.source, indicator.flags + 'g');\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(content)) !== null) {\n if (regions.length >= maxRegions) break;\n const start = Math.max(0, match.index - 100);\n const end = Math.min(content.length, match.index + match[0].length + 100);\n regions.push([start, end]);\n }\n\n if (regions.length >= maxRegions) break;\n }\n\n if (regions.length === 0) return [];\n\n regions.sort((a, b) => a[0] - b[0]);\n\n const merged: Array<[number, number]> = [regions[0]];\n for (let i = 1; i < regions.length; i++) {\n const [start, end] = regions[i];\n const last = merged[merged.length - 1];\n if (start <= last[1]) {\n last[1] = Math.max(last[1], end);\n } else {\n merged.push([start, end]);\n }\n }\n\n return merged.slice(0, maxRegions);\n }\n\n truncateSafely(content: string): string {\n if (content.length <= this.maxContentLength) return content;\n if (!this.preserveAttackPatterns) return content.slice(0, this.maxContentLength);\n\n const attackRegions = this.extractAttackRegions(content);\n if (attackRegions.length === 0) return content.slice(0, this.maxContentLength);\n\n const attackLength = attackRegions.reduce((sum, [s, e]) => sum + (e - s), 0);\n\n if (attackLength >= this.maxContentLength) {\n let result = '';\n let remaining = this.maxContentLength;\n for (const [start, end] of attackRegions) {\n const chunkLen = Math.min(end - start, remaining);\n result += content.slice(start, start + chunkLen);\n remaining -= chunkLen;\n if (remaining <= 0) break;\n }\n return result;\n }\n\n /* v8 ignore start -- attack-region context assembly requires precise content geometry that tests cannot reproduce */\n const parts: string[] = [];\n for (const [start, end] of attackRegions) {\n parts.push(content.slice(start, end));\n }\n\n let remaining = this.maxContentLength - attackLength;\n let lastEnd = 0;\n const contextParts: string[] = [];\n for (const [start, end] of attackRegions) {\n if (lastEnd < start && remaining > 0) {\n const chunkLen = Math.min(start - lastEnd, remaining);\n contextParts.push(content.slice(lastEnd, lastEnd + chunkLen));\n remaining -= chunkLen;\n }\n lastEnd = end;\n }\n\n return [...contextParts, ...parts].join('');\n /* v8 ignore stop */\n }\n\n async preprocess(content: string): Promise<string> {\n if (!content) return '';\n\n let result = this.normalizeUnicode(content);\n result = this.decodeCommonEncodings(result);\n result = this.removeNullBytes(result);\n result = this.removeExcessiveWhitespace(result);\n result = this.truncateSafely(result);\n\n return result;\n }\n\n async preprocessBatch(contents: string[]): Promise<string[]> {\n return Promise.all(contents.map((c) => this.preprocess(c)));\n }\n}\n","export interface MatchResult {\n [index: number]: string | undefined;\n index: number;\n input: string;\n length: number;\n groups?: Record<string, string>;\n}\n\ninterface RE2Instance {\n exec(str: string): MatchResult | null;\n lastIndex: number;\n}\n\ntype RE2Class = new (pattern: string | RegExp, flags?: string) => RE2Instance;\n\nconst DANGEROUS_PATTERNS = [\n /\\(\\.\\*\\)\\+/,\n /\\(\\.\\+\\)\\+/,\n /\\([^)]*\\*\\)\\+/,\n /\\([^)]*\\+\\)\\+/,\n /(?:\\.\\*){2,}/,\n /(?:\\.\\+){2,}/,\n];\n\nconst DEFAULT_TEST_STRINGS = [\n 'a'.repeat(10),\n 'a'.repeat(100),\n 'a'.repeat(1000),\n 'x'.repeat(50) + 'y'.repeat(50),\n '<'.repeat(100) + '>'.repeat(100),\n];\n\nlet RE2Ctor: RE2Class | null = null;\n\nasync function loadRE2(): Promise<RE2Class | null> {\n if (RE2Ctor) return RE2Ctor;\n try {\n const mod = await import('re2-wasm');\n RE2Ctor = mod.RE2 ?? mod.default?.RE2 ?? mod.default;\n return RE2Ctor;\n /* v8 ignore start -- re2-wasm import catch; module available in test env */\n } catch {\n return null;\n }\n /* v8 ignore stop */\n}\n\nexport class PatternCompiler {\n private cache = new Map<string, RE2Instance | RegExp>();\n private cacheOrder: string[] = [];\n private re2Available: boolean | null = null;\n\n constructor(\n private readonly defaultTimeoutMs = 2000,\n private readonly maxCacheSize = 1000,\n ) {\n this.maxCacheSize = Math.min(maxCacheSize, 5000);\n }\n\n private async ensureRE2(): Promise<boolean> {\n if (this.re2Available !== null) return this.re2Available;\n const ctor = await loadRE2();\n this.re2Available = ctor !== null;\n return this.re2Available;\n }\n\n async compile(pattern: string, flags = 'gi'): Promise<RE2Instance | RegExp> {\n const key = `${pattern}:${flags}`;\n\n if (this.cache.has(key)) {\n const idx = this.cacheOrder.indexOf(key);\n if (idx !== -1) {\n this.cacheOrder.splice(idx, 1);\n this.cacheOrder.push(key);\n }\n return this.cache.get(key)!;\n }\n\n if (this.cache.size >= this.maxCacheSize) {\n const oldest = this.cacheOrder.shift();\n if (oldest) this.cache.delete(oldest);\n }\n\n let compiled: RE2Instance | RegExp;\n\n if (await this.ensureRE2()) {\n try {\n compiled = new RE2Ctor!(pattern, flags);\n } catch {\n compiled = new RegExp(pattern, flags);\n }\n } else {\n compiled = new RegExp(pattern, flags);\n }\n\n this.cache.set(key, compiled);\n this.cacheOrder.push(key);\n return compiled;\n }\n\n compileSync(pattern: string, flags = 'gi'): RegExp {\n return new RegExp(pattern, flags);\n }\n\n async safeMatch(\n pattern: string,\n content: string,\n timeoutMs?: number,\n ): Promise<MatchResult | null> {\n try {\n const compiled = await this.compile(pattern);\n return compiled.exec(content);\n } catch {\n return this.fallbackMatch(pattern, content, timeoutMs ?? this.defaultTimeoutMs);\n }\n }\n\n private async fallbackMatch(\n pattern: string,\n content: string,\n timeoutMs: number,\n ): Promise<MatchResult | null> {\n try {\n const { Worker } = await import('node:worker_threads');\n return new Promise<MatchResult | null>((resolve: (v: MatchResult | null) => void) => {\n const workerCode = `\n const { parentPort, workerData } = require('node:worker_threads');\n try {\n const re = new RegExp(workerData.pattern, workerData.flags);\n const result = re.exec(workerData.content);\n parentPort.postMessage({ result });\n } catch (e) {\n parentPort.postMessage({ result: null });\n }\n `;\n const worker = new Worker(workerCode, {\n eval: true,\n workerData: { pattern, content, flags: 'gi' },\n });\n\n /* v8 ignore start -- setTimeout/worker callbacks execute in separate V8 isolate; coverage cannot instrument worker thread code */\n const timer = setTimeout(() => {\n worker.terminate();\n resolve(null);\n }, timeoutMs);\n\n worker.on('message', (msg: { result: MatchResult | null }) => {\n clearTimeout(timer);\n worker.terminate();\n resolve(msg.result);\n });\n\n worker.on('error', () => {\n clearTimeout(timer);\n worker.terminate();\n resolve(null);\n });\n /* v8 ignore stop */\n });\n /* v8 ignore start -- fallback when worker_threads import fails; requires broken Node environment */\n } catch {\n try {\n const re = new RegExp(pattern, 'gi');\n return re.exec(content);\n } catch {\n return null;\n }\n }\n /* v8 ignore stop */\n }\n\n validatePatternSafety(\n pattern: string,\n testStrings?: string[],\n ): [boolean, string] {\n for (const dangerous of DANGEROUS_PATTERNS) {\n if (dangerous.test(pattern)) {\n return [false, `Pattern contains dangerous construct: ${dangerous.source}`];\n }\n }\n\n const strings = testStrings ?? DEFAULT_TEST_STRINGS;\n\n try {\n const compiled = this.compileSync(pattern);\n for (const testStr of strings) {\n const start = performance.now();\n compiled.exec(testStr);\n const elapsed = performance.now() - start;\n if (elapsed > 50) {\n return [false, `Pattern timed out on test string of length ${testStr.length}`];\n }\n }\n } catch (e) {\n return [false, `Pattern validation failed: ${String(e)}`];\n }\n\n return [true, 'Pattern appears safe'];\n }\n\n async batchCompile(\n patterns: string[],\n validate = true,\n ): Promise<Map<string, RE2Instance | RegExp>> {\n const compiled = new Map<string, RE2Instance | RegExp>();\n for (const pattern of patterns) {\n if (validate) {\n const [isSafe] = this.validatePatternSafety(pattern);\n if (!isSafe) continue;\n }\n try {\n compiled.set(pattern, await this.compile(pattern));\n } catch {\n continue;\n }\n }\n return compiled;\n }\n\n async clearCache(): Promise<void> {\n this.cache.clear();\n this.cacheOrder = [];\n }\n}\n","import type { AgentHandlerProtocol } from '../protocols/agent.js';\n\nexport interface PerformanceMetric {\n pattern: string;\n executionTime: number;\n contentLength: number;\n timestamp: Date;\n matched: boolean;\n timeout: boolean;\n}\n\nexport interface PatternStats {\n pattern: string;\n totalExecutions: number;\n totalMatches: number;\n totalTimeouts: number;\n avgExecutionTime: number;\n maxExecutionTime: number;\n minExecutionTime: number;\n recentTimes: number[];\n}\n\nexport interface PatternReport {\n pattern: string;\n patternHash: string;\n totalExecutions: number;\n totalMatches: number;\n totalTimeouts: number;\n matchRate: number;\n timeoutRate: number;\n avgExecutionTime: number;\n maxExecutionTime: number;\n minExecutionTime: number;\n issue?: string;\n}\n\ntype AnomalyCallback = (anomaly: Record<string, unknown>) => void;\n\nconst MAX_RECENT_TIMES = 100;\nconst MAX_PATTERN_LENGTH = 100;\nconst MIN_SAMPLES_FOR_STATS = 10;\n\nfunction mean(values: number[]): number {\n if (values.length === 0) return 0;\n return values.reduce((a, b) => a + b, 0) / values.length;\n}\n\nfunction stdev(values: number[]): number {\n if (values.length <= 1) return 0;\n const avg = mean(values);\n const squareDiffs = values.map((v) => (v - avg) ** 2);\n return Math.sqrt(squareDiffs.reduce((a, b) => a + b, 0) / (values.length - 1));\n}\n\nfunction truncatePattern(pattern: string): string {\n return pattern.length > 50 ? pattern.slice(0, 50) + '...' : pattern;\n}\n\nfunction patternHash(pattern: string): string {\n let hash = 0;\n for (let i = 0; i < pattern.length; i++) {\n hash = (hash << 5) - hash + pattern.charCodeAt(i);\n hash |= 0;\n }\n return String(hash).slice(0, 8);\n}\n\nexport class PerformanceMonitor {\n private readonly anomalyThreshold: number;\n private readonly slowPatternThreshold: number;\n private readonly historySize: number;\n private readonly maxTrackedPatterns: number;\n\n private patternStats = new Map<string, PatternStats>();\n private recentMetrics: PerformanceMetric[] = [];\n private anomalyCallbacks: AnomalyCallback[] = [];\n\n constructor(\n anomalyThreshold = 3.0,\n slowPatternThreshold = 0.1,\n historySize = 1000,\n maxTrackedPatterns = 1000,\n ) {\n this.anomalyThreshold = Math.max(1.0, Math.min(10.0, anomalyThreshold));\n this.slowPatternThreshold = Math.max(0.01, Math.min(10.0, slowPatternThreshold));\n this.historySize = Math.max(100, Math.min(10000, historySize));\n this.maxTrackedPatterns = Math.max(100, Math.min(5000, maxTrackedPatterns));\n }\n\n async recordMetric(\n pattern: string,\n executionTime: number,\n contentLength: number,\n matched: boolean,\n timeout = false,\n agentHandler: AgentHandlerProtocol | null = null,\n correlationId: string | null = null,\n ): Promise<void> {\n let truncatedPattern = pattern;\n if (pattern.length > MAX_PATTERN_LENGTH) {\n truncatedPattern = pattern.slice(0, MAX_PATTERN_LENGTH) + '...[truncated]';\n }\n\n executionTime = Math.max(0, executionTime);\n contentLength = Math.max(0, contentLength);\n\n const metric: PerformanceMetric = {\n pattern: truncatedPattern,\n executionTime,\n contentLength,\n timestamp: new Date(),\n matched,\n timeout,\n };\n\n this.recentMetrics.push(metric);\n /* v8 ignore start -- V8 coverage sometimes misses inline overflow guard despite tests exercising it */\n if (this.recentMetrics.length > this.historySize) {\n this.recentMetrics.shift();\n }\n /* v8 ignore stop */\n\n if (!this.patternStats.has(truncatedPattern)) {\n /* v8 ignore start -- first-time pattern tracking and maxTrackedPatterns overflow; V8 misses inline object creation */\n if (this.patternStats.size >= this.maxTrackedPatterns) {\n const oldestKey = this.patternStats.keys().next().value!;\n this.patternStats.delete(oldestKey);\n }\n /* v8 ignore stop */\n this.patternStats.set(truncatedPattern, {\n pattern: truncatedPattern,\n totalExecutions: 0,\n totalMatches: 0,\n totalTimeouts: 0,\n avgExecutionTime: 0,\n maxExecutionTime: 0,\n minExecutionTime: Infinity,\n recentTimes: [],\n });\n }\n\n const stats = this.patternStats.get(truncatedPattern)!;\n stats.totalExecutions++;\n if (matched) stats.totalMatches++;\n if (timeout) stats.totalTimeouts++;\n\n if (!timeout) {\n stats.recentTimes.push(executionTime);\n if (stats.recentTimes.length > MAX_RECENT_TIMES) {\n stats.recentTimes.shift();\n }\n stats.maxExecutionTime = Math.max(stats.maxExecutionTime, executionTime);\n stats.minExecutionTime = Math.min(stats.minExecutionTime, executionTime);\n if (stats.recentTimes.length > 0) {\n stats.avgExecutionTime = mean(stats.recentTimes);\n }\n }\n\n await this.checkAnomalies(metric, agentHandler, correlationId);\n }\n\n private async checkAnomalies(\n metric: PerformanceMetric,\n agentHandler: AgentHandlerProtocol | null,\n correlationId: string | null,\n ): Promise<void> {\n const anomalies: Array<Record<string, unknown>> = [];\n\n if (metric.timeout) {\n anomalies.push({\n type: 'timeout',\n pattern: metric.pattern,\n contentLength: metric.contentLength,\n });\n } else if (metric.executionTime > this.slowPatternThreshold) {\n anomalies.push({\n type: 'slow_execution',\n pattern: metric.pattern,\n executionTime: metric.executionTime,\n contentLength: metric.contentLength,\n });\n }\n\n const stats = this.patternStats.get(metric.pattern);\n if (stats && stats.recentTimes.length >= MIN_SAMPLES_FOR_STATS) {\n const avgTime = mean(stats.recentTimes);\n const stdTime = stdev(stats.recentTimes);\n if (stdTime > 0) {\n const zScore = (metric.executionTime - avgTime) / stdTime;\n if (Math.abs(zScore) > this.anomalyThreshold) {\n anomalies.push({\n type: 'statistical_anomaly',\n pattern: metric.pattern,\n executionTime: metric.executionTime,\n zScore,\n avgTime,\n stdTime,\n });\n }\n }\n }\n\n if (agentHandler) {\n for (const anomaly of anomalies) {\n try {\n await agentHandler.sendEvent({\n timestamp: new Date(),\n eventType: `pattern_anomaly_${anomaly['type']}`,\n ipAddress: 'system',\n actionTaken: 'anomaly_detected',\n reason: `Pattern performance anomaly: ${anomaly['type']}`,\n metadata: { component: 'PerformanceMonitor', correlationId, ...anomaly },\n });\n } catch {\n // never throw from anomaly reporting\n }\n }\n }\n\n for (const anomaly of anomalies) {\n const safe: Record<string, unknown> = { ...anomaly };\n if (typeof safe['pattern'] === 'string') {\n safe['pattern'] = truncatePattern(safe['pattern'] as string);\n safe['patternHash'] = patternHash(anomaly['pattern'] as string);\n }\n for (const callback of this.anomalyCallbacks) {\n try { callback(safe); } catch { /* ignore */ }\n }\n }\n }\n\n getPatternReport(pattern: string): PatternReport | null {\n let key = pattern;\n if (key.length > MAX_PATTERN_LENGTH) {\n key = key.slice(0, MAX_PATTERN_LENGTH) + '...[truncated]';\n }\n\n const stats = this.patternStats.get(key);\n if (!stats) return null;\n\n return {\n pattern: truncatePattern(key),\n patternHash: patternHash(key),\n totalExecutions: stats.totalExecutions,\n totalMatches: stats.totalMatches,\n totalTimeouts: stats.totalTimeouts,\n matchRate: stats.totalMatches / Math.max(stats.totalExecutions, 1),\n timeoutRate: stats.totalTimeouts / Math.max(stats.totalExecutions, 1),\n avgExecutionTime: Math.round(stats.avgExecutionTime * 10000) / 10000,\n maxExecutionTime: Math.round(stats.maxExecutionTime * 10000) / 10000,\n minExecutionTime: Math.round(\n (stats.minExecutionTime === Infinity ? 0 : stats.minExecutionTime) * 10000,\n ) / 10000,\n };\n }\n\n getSlowPatterns(limit = 10): PatternReport[] {\n const entries = [...this.patternStats.entries()]\n .filter(([, s]) => s.recentTimes.length > 0)\n .sort(([, a], [, b]) => b.avgExecutionTime - a.avgExecutionTime)\n .slice(0, limit);\n\n const reports: PatternReport[] = [];\n for (const [pattern] of entries) {\n const report = this.getPatternReport(pattern);\n if (report) reports.push(report);\n }\n return reports;\n }\n\n getProblematicPatterns(): PatternReport[] {\n const problematic: PatternReport[] = [];\n\n for (const [pattern, stats] of this.patternStats) {\n if (stats.totalExecutions === 0) continue;\n\n const timeoutRate = stats.totalTimeouts / stats.totalExecutions;\n if (timeoutRate > 0.1) {\n const report = this.getPatternReport(pattern);\n if (report) {\n report.issue = 'high_timeout_rate';\n problematic.push(report);\n }\n } else if (stats.avgExecutionTime > this.slowPatternThreshold) {\n const report = this.getPatternReport(pattern);\n if (report) {\n report.issue = 'consistently_slow';\n problematic.push(report);\n }\n }\n }\n\n return problematic;\n }\n\n getSummaryStats(): Record<string, unknown> {\n if (this.recentMetrics.length === 0) {\n return { totalExecutions: 0, avgExecutionTime: 0, timeoutRate: 0, matchRate: 0 };\n }\n\n const recentTimes = this.recentMetrics\n .filter((m) => !m.timeout)\n .map((m) => m.executionTime);\n const timeouts = this.recentMetrics.filter((m) => m.timeout).length;\n const matches = this.recentMetrics.filter((m) => m.matched).length;\n const total = this.recentMetrics.length;\n\n return {\n totalExecutions: total,\n avgExecutionTime: recentTimes.length > 0 ? mean(recentTimes) : 0,\n maxExecutionTime: recentTimes.length > 0 ? Math.max(...recentTimes) : 0,\n minExecutionTime: recentTimes.length > 0 ? Math.min(...recentTimes) : 0,\n timeoutRate: timeouts / total,\n matchRate: matches / total,\n totalPatterns: this.patternStats.size,\n };\n }\n\n registerAnomalyCallback(callback: AnomalyCallback): void {\n this.anomalyCallbacks.push(callback);\n }\n\n async clearStats(): Promise<void> {\n this.patternStats.clear();\n this.recentMetrics = [];\n }\n\n async removePatternStats(pattern: string): Promise<void> {\n this.patternStats.delete(pattern);\n }\n}\n","const ATTACK_KEYWORDS: Record<string, Set<string>> = {\n xss: new Set([\n 'script', 'javascript', 'onerror', 'onload', 'onclick', 'onmouseover',\n 'alert', 'eval', 'document', 'cookie', 'window', 'location',\n ]),\n sql: new Set([\n 'select', 'union', 'insert', 'update', 'delete', 'drop', 'from',\n 'where', 'order', 'group', 'having', 'concat', 'substring', 'database',\n 'table', 'column',\n ]),\n command: new Set([\n 'exec', 'system', 'shell', 'cmd', 'bash', 'powershell', 'wget',\n 'curl', 'nc', 'netcat', 'chmod', 'chown', 'sudo', 'passwd',\n ]),\n path: new Set(['etc', 'passwd', 'shadow', 'hosts', 'proc', 'boot', 'win', 'ini']),\n template: new Set([\n 'render', 'template', 'jinja', 'mustache', 'handlebars', 'ejs', 'pug', 'twig',\n ]),\n};\n\nconst ATTACK_STRUCTURES: Record<string, RegExp> = {\n tag_like: /<[^>]+>/gi,\n function_call: /\\w+\\s*\\([^)]*\\)/gi,\n command_chain: /[;&|]{1,2}/g,\n path_traversal: /\\.{2,}[/\\\\]/g,\n url_pattern: /[a-z]+:\\/\\//gi,\n};\n\nconst PATTERN_CHECKS: Record<string, [RegExp, string]> = {\n xss: [/<[^>]+>/g, ''],\n sql: [/\\b(?:union|select|from|where)\\b/gi, ''],\n command: [/[;&|]/g, ''],\n path: [/\\.{2,}[/\\\\]/g, ''],\n};\n\nconst INJECTION_KEYWORDS = ['eval', 'exec', 'compile', '__import__', 'globals', 'locals'];\n\nconst MAX_CONTENT_LENGTH = 50000;\nconst MAX_TOKENS = 1000;\nconst MAX_ENTROPY_LENGTH = 10000;\nconst MAX_SCAN_LENGTH = 10000;\nconst MAX_AST_LENGTH = 1000;\n\nexport interface SemanticAnalysis {\n attackProbabilities: Record<string, number>;\n entropy: number;\n encodingLayers: number;\n isObfuscated: boolean;\n suspiciousPatterns: Array<{\n type: string;\n pattern: string;\n position: number;\n context: string;\n }>;\n codeInjectionRisk: number;\n tokenCount: number;\n}\n\nexport class SemanticAnalyzer {\n extractTokens(content: string): string[] {\n let truncated = content;\n if (truncated.length > MAX_CONTENT_LENGTH) {\n truncated = truncated.slice(0, MAX_CONTENT_LENGTH);\n }\n\n truncated = truncated.replace(/\\s+/g, ' ');\n\n const wordTokens = (truncated.toLowerCase().match(/\\b\\w+\\b/g) ?? []).slice(0, MAX_TOKENS);\n\n const specialPatterns: string[] = [];\n for (const [, regex] of Object.entries(ATTACK_STRUCTURES)) {\n const re = new RegExp(regex.source, regex.flags);\n let match: RegExpExecArray | null;\n while ((match = re.exec(truncated)) !== null && specialPatterns.length < 50) {\n specialPatterns.push(match[0]);\n }\n if (specialPatterns.length >= 50) break;\n }\n\n return [...wordTokens, ...specialPatterns].slice(0, MAX_TOKENS);\n }\n\n calculateEntropy(content: string): number {\n if (!content) return 0.0;\n\n const truncated = content.length > MAX_ENTROPY_LENGTH\n ? content.slice(0, MAX_ENTROPY_LENGTH)\n : content;\n\n const counts = new Map<string, number>();\n for (const char of truncated) {\n counts.set(char, (counts.get(char) ?? 0) + 1);\n }\n\n const length = truncated.length;\n let entropy = 0.0;\n for (const count of counts.values()) {\n const probability = count / length;\n if (probability > 0) {\n entropy -= probability * Math.log2(probability);\n }\n }\n\n return entropy;\n }\n\n detectEncodingLayers(content: string): number {\n const truncated = content.length > MAX_SCAN_LENGTH\n ? content.slice(0, MAX_SCAN_LENGTH)\n : content;\n\n let layers = 0;\n\n if (/%[0-9a-fA-F]{2}/.test(truncated)) layers++;\n if (/[A-Za-z0-9+/]{4,}={0,2}/.test(truncated)) layers++;\n if (/(?:0x)?[0-9a-fA-F]{4,}/.test(truncated)) layers++;\n if (/\\\\u[0-9a-fA-F]{4}/.test(truncated)) layers++;\n if (/&[#\\w]+;/.test(truncated)) layers++;\n\n return layers;\n }\n\n analyzeAttackProbability(content: string): Record<string, number> {\n const tokens = this.extractTokens(content);\n const tokenSet = new Set(tokens);\n const probabilities: Record<string, number> = {};\n\n for (const [attackType, keywords] of Object.entries(ATTACK_KEYWORDS)) {\n let matches = 0;\n for (const token of tokenSet) {\n if (keywords.has(token)) matches++;\n }\n const baseScore = keywords.size > 0 ? matches / keywords.size : 0;\n\n let patternBoost = 0;\n const check = PATTERN_CHECKS[attackType];\n /* v8 ignore next -- branch-only gap in regex test condition; attackType always matches a PATTERN_CHECKS key */\n if (check) {\n const [re] = check;\n if (new RegExp(re.source, re.flags).test(content)) {\n patternBoost = 0.3;\n }\n }\n\n probabilities[attackType] = Math.min(baseScore + patternBoost, 1.0);\n }\n\n return probabilities;\n }\n\n detectObfuscation(content: string): boolean {\n /* v8 ignore next -- branch-only gap; V8 marks the return but not the false branch of the condition */\n if (this.calculateEntropy(content) > 4.5) return true;\n if (this.detectEncodingLayers(content) > 2) return true;\n\n const specialChars = (content.match(/[^a-zA-Z0-9\\s]/g) ?? []).length;\n if (specialChars / Math.max(content.length, 1) > 0.4) return true;\n\n if (/\\S{100,}/.test(content)) return true;\n\n return false;\n }\n\n extractSuspiciousPatterns(content: string): SemanticAnalysis['suspiciousPatterns'] {\n const patterns: SemanticAnalysis['suspiciousPatterns'] = [];\n\n for (const [name, regex] of Object.entries(ATTACK_STRUCTURES)) {\n const re = new RegExp(regex.source, regex.flags);\n let match: RegExpExecArray | null;\n while ((match = re.exec(content)) !== null) {\n const contextStart = Math.max(0, match.index - 20);\n const contextEnd = Math.min(content.length, match.index + match[0].length + 20);\n patterns.push({\n type: name,\n pattern: match[0],\n position: match.index,\n context: content.slice(contextStart, contextEnd),\n });\n }\n }\n\n return patterns;\n }\n\n analyzeCodeInjectionRisk(content: string): number {\n let riskScore = 0.0;\n\n /* v8 ignore next -- branch-only gap in regex test condition */\n if (/[{}].*[{}]/.test(content)) riskScore += 0.2;\n if (/\\w+\\s*\\([^)]*\\)/.test(content)) riskScore += 0.2;\n /* v8 ignore next -- branch-only gap in regex test condition */\n if (/[$@]\\w+/.test(content)) riskScore += 0.1;\n if (/[=+\\-*/]{2,}/.test(content)) riskScore += 0.1;\n\n if (content.length <= MAX_AST_LENGTH) {\n try {\n const acorn = require('acorn');\n acorn.parse(content, { ecmaVersion: 'latest', sourceType: 'module' });\n riskScore += 0.3;\n } catch {\n // not valid JS, no risk boost\n }\n }\n\n for (const keyword of INJECTION_KEYWORDS) {\n if (new RegExp(`\\\\b${keyword}\\\\b`, 'i').test(content)) {\n riskScore += 0.2;\n break;\n }\n }\n\n return Math.min(riskScore, 1.0);\n }\n\n analyze(content: string): SemanticAnalysis {\n return {\n attackProbabilities: this.analyzeAttackProbability(content),\n entropy: this.calculateEntropy(content),\n encodingLayers: this.detectEncodingLayers(content),\n isObfuscated: this.detectObfuscation(content),\n suspiciousPatterns: this.extractSuspiciousPatterns(content),\n codeInjectionRisk: this.analyzeCodeInjectionRisk(content),\n tokenCount: this.extractTokens(content).length,\n };\n }\n\n getThreatScore(analysis: SemanticAnalysis): number {\n let score = 0.0;\n\n const probs = analysis.attackProbabilities;\n const maxProb = Object.values(probs).length > 0\n ? Math.max(...Object.values(probs))\n : 0;\n score += maxProb * 0.3;\n\n if (analysis.isObfuscated) score += 0.2;\n\n if (analysis.encodingLayers > 0) {\n score += Math.min(analysis.encodingLayers * 0.1, 0.2);\n }\n\n score += analysis.codeInjectionRisk * 0.2;\n\n if (analysis.suspiciousPatterns.length > 0) {\n score += Math.min(analysis.suspiciousPatterns.length * 0.05, 0.1);\n }\n\n return Math.min(score, 1.0);\n }\n}\n","import type { ResolvedSecurityConfig } from '../models/config.js';\nimport type { Logger } from '../models/logger.js';\nimport { ContentPreprocessor } from '../detection-engine/preprocessor.js';\nimport { PatternCompiler } from '../detection-engine/compiler.js';\nimport { PerformanceMonitor } from '../detection-engine/monitor.js';\nimport { SemanticAnalyzer } from '../detection-engine/semantic.js';\nimport type { AgentHandlerProtocol } from '../protocols/agent.js';\nimport type { RedisManager } from './redis.js';\n\nconst CTX_XSS: ReadonlySet<string> = new Set(['query_param', 'header', 'request_body', 'unknown']);\nconst CTX_SQLI: ReadonlySet<string> = new Set(['query_param', 'request_body', 'unknown']);\nconst CTX_DIR_TRAVERSAL: ReadonlySet<string> = new Set(['url_path', 'query_param', 'request_body', 'unknown']);\nconst CTX_CMD_INJECTION: ReadonlySet<string> = new Set(['query_param', 'request_body', 'unknown']);\nconst CTX_FILE_INCLUSION: ReadonlySet<string> = new Set(['url_path', 'query_param', 'request_body', 'unknown']);\nconst CTX_LDAP: ReadonlySet<string> = new Set(['query_param', 'request_body', 'unknown']);\nconst CTX_XML: ReadonlySet<string> = new Set(['header', 'request_body', 'unknown']);\nconst CTX_SSRF: ReadonlySet<string> = new Set(['query_param', 'request_body', 'unknown']);\nconst CTX_NOSQL: ReadonlySet<string> = new Set(['query_param', 'request_body', 'unknown']);\nconst CTX_FILE_UPLOAD: ReadonlySet<string> = new Set(['header', 'request_body', 'unknown']);\nconst CTX_PATH_TRAVERSAL: ReadonlySet<string> = new Set(['url_path', 'query_param', 'request_body', 'unknown']);\nconst CTX_TEMPLATE: ReadonlySet<string> = new Set(['query_param', 'request_body', 'unknown']);\nconst CTX_HTTP_SPLIT: ReadonlySet<string> = new Set(['header', 'query_param', 'request_body', 'unknown']);\nconst CTX_SENSITIVE_FILE: ReadonlySet<string> = new Set(['url_path', 'request_body', 'unknown']);\nconst CTX_CMS_PROBING: ReadonlySet<string> = new Set(['url_path', 'request_body', 'unknown']);\nconst CTX_RECON: ReadonlySet<string> = new Set(['url_path', 'unknown']);\nconst CTX_ALL: ReadonlySet<string> = new Set(['query_param', 'header', 'url_path', 'request_body', 'unknown']);\n\nconst KNOWN_CONTEXTS = new Set(['query_param', 'header', 'url_path', 'request_body', 'unknown']);\n\nconst PATTERN_DEFINITIONS: Array<[string, ReadonlySet<string>]> = [\n [String.raw`<script[^>]*>[^<]*<\\/script\\s*>`, CTX_XSS],\n [String.raw`javascript:\\s*[^\\s]+`, CTX_XSS],\n [String.raw`(?:on(?:error|load|click|mouseover|submit|mouse|unload|change|focus|blur|drag))=(?:[\"'][^\"']*[\"']|[^\\s>]+)`, CTX_XSS],\n [String.raw`(?:<[^>]+\\s+(?:href|src|data|action)\\s*=[\\s\"']*(?:javascript|vbscript|data):)`, CTX_XSS],\n [String.raw`(?:<[^>]+style\\s*=[\\s\"']*[^>\"']*(?:expression|behavior|url)\\s*\\([^)]*\\))`, CTX_XSS],\n [String.raw`(?:<object[^>]*>[\\s\\S]*<\\/object\\s*>)`, CTX_XSS],\n [String.raw`(?:<embed[^>]*>[\\s\\S]*<\\/embed\\s*>)`, CTX_XSS],\n [String.raw`(?:<applet[^>]*>[\\s\\S]*<\\/applet\\s*>)`, CTX_XSS],\n [String.raw`SELECT\\s+[\\w\\s,*]+\\s+FROM\\s+[\\w\\s._]+`, CTX_SQLI],\n [String.raw`UNION\\s+(?:ALL\\s+)?SELECT`, CTX_SQLI],\n [String.raw`('\\s*(?:OR|AND)\\s*[(\\s]*'?[\\d\\w]+\\s*(?:=|LIKE|<|>|<=|>=)\\s*[(\\s]*'?[\\d\\w]+)`, CTX_SQLI],\n [String.raw`(UNION\\s+(?:ALL\\s+)?SELECT\\s+(?:NULL[,\\s]*)+|\\(\\s*SELECT\\s+(?:@@|VERSION))`, CTX_SQLI],\n [String.raw`(?:INTO\\s+(?:OUTFILE|DUMPFILE)\\s+'[^']+')`, CTX_SQLI],\n [String.raw`(?:LOAD_FILE\\s*\\([^)]+\\))`, CTX_SQLI],\n [String.raw`(?:BENCHMARK\\s*\\(\\s*\\d+\\s*,)`, CTX_SQLI],\n [String.raw`(?:SLEEP\\s*\\(\\s*\\d+\\s*\\))`, CTX_SQLI],\n [String.raw`(?:\\/\\*![0-9]*\\s*(?:OR|AND|UNION|SELECT|INSERT|DELETE|DROP|CONCAT|CHAR|UPDATE)\\b)`, CTX_SQLI],\n [String.raw`(?:\\.\\.\\/|\\.\\.\\\\)(?:\\.\\.\\/|\\.\\.\\\\)+`, CTX_DIR_TRAVERSAL],\n [String.raw`(?:/etc/(?:passwd|shadow|group|hosts|motd|issue|mysql/my.cnf|ssh/ssh_config)$)`, CTX_DIR_TRAVERSAL],\n [String.raw`(?:boot\\.ini|win\\.ini|system\\.ini|config\\.sys)\\s*$`, CTX_DIR_TRAVERSAL],\n [String.raw`(?:\\/proc\\/self\\/environ$)`, CTX_DIR_TRAVERSAL],\n [String.raw`(?:\\/var\\/log\\/[^/]+$)`, CTX_DIR_TRAVERSAL],\n [String.raw`;\\s*(?:ls|cat|rm|chmod|chown|wget|curl|nc|netcat|ping|telnet)\\s+-[a-zA-Z]+\\s+`, CTX_CMD_INJECTION],\n [String.raw`\\|\\s*(?:wget|curl|fetch|lwp-download|lynx|links|GET)\\s+`, CTX_CMD_INJECTION],\n [String.raw`(?:[;&|` + '`' + String.raw`]\\s*(?:\\$\\([^)]+\\)|\\$\\{[^}]+\\}))`, CTX_CMD_INJECTION],\n [String.raw`(?:^|;)\\s*(?:bash|sh|ksh|csh|tsch|zsh|ash)\\s+-[a-zA-Z]+`, CTX_CMD_INJECTION],\n [String.raw`\\b(?:eval|system|exec|shell_exec|passthru|popen|proc_open)\\s*\\(`, CTX_CMD_INJECTION],\n [String.raw`(?:php|data|zip|rar|file|glob|expect|input|phpinfo|zlib|phar|ssh2|rar|ogg|expect)://[^\\s]+`, CTX_FILE_INCLUSION],\n [String.raw`(?:\\/\\/[0-9a-zA-Z]([-.\\w]*[0-9a-zA-Z])*(:[0-9]+)?(?:\\/?)?(?:[a-zA-Z0-9\\-.,?'/\\\\+&amp;%$#_]*)?)`, CTX_FILE_INCLUSION],\n [String.raw`\\(\\s*[|&]\\s*\\(\\s*[^)]+=[*]`, CTX_LDAP],\n [String.raw`(?:\\*(?:[\\s\\d\\w]+\\s*=|=\\s*[\\d\\w\\s]+))`, CTX_LDAP],\n [String.raw`(?:\\(\\s*[&|]\\s*)`, CTX_LDAP],\n [String.raw`<!(?:ENTITY|DOCTYPE)[^>]+SYSTEM[^>]+>`, CTX_XML],\n [String.raw`(?:<!\\[CDATA\\[.*?\\]\\]>)`, CTX_XML],\n [String.raw`(?:<\\?xml.*?\\?>)`, CTX_XML],\n [String.raw`(?:^|\\s|/)(?:localhost|127\\.0\\.0\\.1|0\\.0\\.0\\.0|\\[::(?:\\d*)\\]|(?:169\\.254|192\\.168|10\\.|172\\.(?:1[6-9]|2[0-9]|3[01]))\\.\\d+)(?:\\s|$|/)`, CTX_SSRF],\n [String.raw`(?:file|dict|gopher|jar|tftp)://[^\\s]+`, CTX_SSRF],\n [String.raw`\\{\\s*\\$(?:where|gt|lt|ne|eq|regex|in|nin|all|size|exists|type|mod|options):`, CTX_NOSQL],\n [String.raw`(?:\\{\\s*\\$[a-zA-Z]+\\s*:\\s*(?:\\{|\\[))`, CTX_NOSQL],\n [String.raw`filename=[\"'].*?\\.(?:php\\d*|phar|phtml|exe|jsp|asp|aspx|sh|bash|rb|py|pl|cgi|com|bat|cmd|vbs|vbe|js|ws|wsf|msi|hta)[\"']`, CTX_FILE_UPLOAD],\n [String.raw`(?:%2e%2e|%252e%252e|%uff0e%uff0e|%c0%ae%c0%ae|%e0%40%ae|%c0%ae%e0%80%ae|%25c0%25ae)/`, CTX_PATH_TRAVERSAL],\n [String.raw`\\{\\{\\s*[^}]+(?:system|exec|popen|eval|require|include)\\s*\\}\\}`, CTX_TEMPLATE],\n [String.raw`\\{%\\s*[^%]+(?:system|exec|popen|eval|require|include)\\s*%\\}`, CTX_TEMPLATE],\n [String.raw`[\\r\\n]\\s*(?:HTTP\\/[0-9.]+|Location:|Set-Cookie:)`, CTX_HTTP_SPLIT],\n [String.raw`(?:^|/)\\.env(?:\\.\\w+)?(?:\\?|$|/)`, CTX_SENSITIVE_FILE],\n [String.raw`(?:^|/)[\\w-]*config[\\w-]*\\.(?:env|yml|yaml|json|toml|ini|xml|conf)(?:\\?|$)`, CTX_SENSITIVE_FILE],\n [String.raw`(?:^|/)[\\w./-]*\\.map(?:\\?|$)`, CTX_SENSITIVE_FILE],\n [String.raw`(?:^|/)[\\w./-]*\\.(?:ts|tsx|jsx|py|rb|java|go|rs|php|pl|sh|sql)(?:\\?|$)`, CTX_SENSITIVE_FILE],\n [String.raw`(?:^|/)\\.(?:git|svn|hg|bzr)(?:/|$)`, CTX_SENSITIVE_FILE],\n [String.raw`(?:^|/)(?:wp-(?:admin|login|content|includes|config)|administrator|xmlrpc)\\.?(?:php)?(?:/|$|\\?)`, CTX_CMS_PROBING],\n [String.raw`(?:^|/)(?:phpinfo|info|test|php_info)\\.php(?:\\?|$)`, CTX_CMS_PROBING],\n [String.raw`(?:^|/)[\\w./-]*\\.(?:bak|backup|old|orig|save|swp|swo|tmp|temp)(?:\\?|$)`, CTX_CMS_PROBING],\n [String.raw`(?:^|/)(?:\\.htaccess|\\.htpasswd|\\.DS_Store|Thumbs\\.db|\\.npmrc|\\.dockerenv|web\\.config)(?:\\?|$)`, CTX_CMS_PROBING],\n [String.raw`(?:^|/)[\\w./-]*\\.(?:asp|aspx|jsp|jsa|jhtml|shtml|cfm|cgi|do|action|lua|inc|woa|nsf|esp|html?|js|css|properties|png|gif|jpg|jpeg|svg|webp|bmp|pl)(?:\\?|$)`, CTX_RECON],\n [String.raw`^/(?:api|rest|v\\d+|management|system|version|status|config|config_dump|credentials)(?:/|$|\\?)`, CTX_RECON],\n [String.raw`^/admin(?:istrator)?(?:[./?\\-]|$)`, CTX_RECON],\n [String.raw`^/(?:login|logon|signin)(?:[./?\\-]|$|/)`, CTX_RECON],\n [String.raw`(?:^|/)account/login(?:\\?|$|/)`, CTX_RECON],\n [String.raw`(?:^|/)(?:actuator|server-status|telescope)(?:/|$|\\?)`, CTX_RECON],\n [String.raw`(?:CSCOE|dana-(?:na|cached)|sslvpn|RDWeb|/owa/|/ecp/|global-protect|ssl-vpn/|svpn/|sonicui|/remote/login|myvpn|vpntunnel|versa/login)`, CTX_RECON],\n [String.raw`(?:^|/)(?:geoserver|confluence|nifi|ScadaBR|pandora_console|centreon|kylin|decisioncenter|evox|MagicInfo|metasys|officescan|helpdesk|ignite)(?:/|$|\\?|\\.|\\-)`, CTX_RECON],\n [String.raw`(?:^|/)cgi-(?:bin|mod)/`, CTX_RECON],\n [String.raw`(?:^|/)(?:HNAP1|IPCamDesc\\.xml|SDK/webLanguage)(?:\\?|$|/)`, CTX_RECON],\n [String.raw`^/(?:scripts|language|languages|images|css|img)/`, CTX_RECON],\n [String.raw`(?:^|/)(?:robots\\.txt|sitemap\\.xml|security\\.txt|readme\\.txt|README\\.md|CHANGELOG|pom\\.xml|build\\.gradle|appsettings\\.json|crossdomain\\.xml)(?:\\?|$|\\.)`, CTX_RECON],\n [String.raw`(?:^|/)(?:sap|ise|nidp|cslu|rustfs|developmentserver|fog/management|lms/db|json/login_session|sms_mp|plugin/webs_model|wsman|am_bin)(?:/|$|\\?)`, CTX_RECON],\n [String.raw`(?:nmaplowercheck|nice\\s+ports|Trinity\\.txt)`, CTX_RECON],\n [String.raw`(?:^|/)\\.(?:openclaw|clawdbot)(?:/|$)`, CTX_RECON],\n [String.raw`^/(?:default|inicio|indice|localstart)(?:\\.|/|$|\\?)`, CTX_RECON],\n [String.raw`(?:^|/)(?:\\.streamlit|\\.gpt-pilot|\\.aider|\\.cursor|\\.windsurf|\\.copilot|\\.devcontainer)(?:/|$)`, CTX_RECON],\n [String.raw`(?:^|/)(?:docker-compose|Dockerfile|Makefile|Vagrantfile|Jenkinsfile|Procfile)(?:\\.ya?ml)?(?:\\?|$)`, CTX_RECON],\n [String.raw`(?:^|/)[\\w./-]*(?:secrets?|credentials?)\\.(?:py|json|yml|yaml|toml|txt|env|xml|conf|cfg)(?:\\?|$)`, CTX_RECON],\n [String.raw`(?:^|/)autodiscover/`, CTX_RECON],\n [String.raw`^/dns-query(?:\\?|$)`, CTX_RECON],\n [String.raw`(?:^|/)\\.git/(?:refs|index|HEAD|objects|logs)(?:/|$)`, CTX_RECON],\n];\n\nexport interface DetectionResult {\n isThreat: boolean;\n threatScore: number;\n threats: Array<{\n pattern: string;\n context: string;\n matchedContent: string;\n detectionMethod: string;\n }>;\n executionTime: number;\n timeouts: string[];\n correlationId: string | null;\n originalLength: number;\n processedLength: number;\n}\n\nexport class SusPatternsManager {\n private compiler: PatternCompiler;\n private preprocessor: ContentPreprocessor;\n private semantic: SemanticAnalyzer;\n private monitor: PerformanceMonitor;\n private customPatterns = new Set<string>();\n private compiledCustomContexts = new Map<string, ReadonlySet<string>>();\n private redisHandler: RedisManager | null = null;\n private agentHandler: AgentHandlerProtocol | null = null;\n private semanticThreshold: number;\n\n constructor(\n config: ResolvedSecurityConfig,\n private readonly logger: Logger,\n ) {\n this.compiler = new PatternCompiler(config.detectionCompilerTimeout * 1000, config.detectionMaxTrackedPatterns);\n this.preprocessor = new ContentPreprocessor(config.detectionMaxContentLength, config.detectionPreserveAttackPatterns);\n this.semantic = new SemanticAnalyzer();\n this.monitor = new PerformanceMonitor(\n config.detectionAnomalyThreshold,\n config.detectionSlowPatternThreshold,\n config.detectionMonitorHistorySize,\n config.detectionMaxTrackedPatterns,\n );\n this.semanticThreshold = config.detectionSemanticThreshold;\n }\n\n async initializeRedis(redisHandler: RedisManager): Promise<void> {\n this.redisHandler = redisHandler;\n const cached = await redisHandler.getKey('patterns', 'custom');\n if (typeof cached === 'string' && cached.length > 0) {\n for (const p of cached.split(',')) {\n if (p.trim()) {\n this.customPatterns.add(p.trim());\n this.compiledCustomContexts.set(p.trim(), CTX_ALL);\n }\n }\n }\n }\n\n async initializeAgent(agentHandler: AgentHandlerProtocol): Promise<void> {\n this.agentHandler = agentHandler;\n }\n\n private normalizeContext(context: string): string {\n const parts = context.split(':');\n const normalized = parts[0].toLowerCase();\n return KNOWN_CONTEXTS.has(normalized) ? normalized : 'unknown';\n }\n\n async detect(\n content: string,\n ipAddress: string,\n context = 'unknown',\n correlationId: string | null = null,\n ): Promise<DetectionResult> {\n const startTime = performance.now();\n const originalLength = content.length;\n\n const processed = await this.preprocessor.preprocess(content);\n const normalizedCtx = this.normalizeContext(context);\n\n const threats: DetectionResult['threats'] = [];\n const timeouts: string[] = [];\n\n for (const [pattern, contexts] of PATTERN_DEFINITIONS) {\n if (!contexts.has(normalizedCtx)) continue;\n\n const patternStart = performance.now();\n try {\n const match = await this.compiler.safeMatch(pattern, processed);\n const elapsed = (performance.now() - patternStart) / 1000;\n\n await this.monitor.recordMetric(pattern, elapsed, processed.length, match !== null, false, this.agentHandler, correlationId);\n\n if (match) {\n threats.push({\n pattern,\n context: normalizedCtx,\n matchedContent: String(match[0] ?? '').slice(0, 200),\n detectionMethod: 'regex',\n });\n }\n /* v8 ignore start -- custom pattern context check; requires pattern compiler to throw during safeMatch */\n } catch {\n timeouts.push(pattern);\n const elapsed = (performance.now() - patternStart) / 1000;\n await this.monitor.recordMetric(pattern, elapsed, processed.length, false, true, this.agentHandler, correlationId);\n }\n /* v8 ignore stop */\n }\n\n for (const customPattern of this.customPatterns) {\n const ctxSet = this.compiledCustomContexts.get(customPattern) ?? CTX_ALL;\n if (!ctxSet.has(normalizedCtx)) continue;\n\n try {\n const match = await this.compiler.safeMatch(customPattern, processed);\n if (match) {\n threats.push({\n pattern: customPattern,\n context: normalizedCtx,\n matchedContent: String(match[0] ?? '').slice(0, 200),\n detectionMethod: 'regex_custom',\n });\n }\n /* v8 ignore start -- custom pattern timeout catch; requires safeMatch to throw */\n } catch {\n timeouts.push(customPattern);\n }\n /* v8 ignore stop */\n }\n\n const analysis = this.semantic.analyze(processed);\n const semanticScore = this.semantic.getThreatScore(analysis);\n\n if (semanticScore >= this.semanticThreshold) {\n const topAttack = Object.entries(analysis.attackProbabilities)\n .sort(([, a], [, b]) => b - a)[0];\n if (topAttack) {\n threats.push({\n pattern: `semantic:${topAttack[0]}`,\n context: normalizedCtx,\n matchedContent: `score=${semanticScore.toFixed(3)}`,\n detectionMethod: 'semantic',\n });\n }\n }\n\n const regexScore = threats.some((t) => t.detectionMethod.startsWith('regex')) ? 1.0 : 0.0;\n const threatScore = Math.max(regexScore, semanticScore);\n\n const executionTime = (performance.now() - startTime) / 1000;\n\n return {\n isThreat: threats.length > 0,\n threatScore,\n threats,\n executionTime,\n timeouts,\n correlationId,\n originalLength,\n processedLength: processed.length,\n };\n }\n\n async detectPatternMatch(\n content: string,\n ipAddress: string,\n context = 'unknown',\n correlationId: string | null = null,\n ): Promise<[boolean, string | null]> {\n const result = await this.detect(content, ipAddress, context, correlationId);\n if (result.isThreat && result.threats.length > 0) {\n return [true, result.threats[0].pattern];\n }\n return [false, null];\n }\n\n async addPattern(pattern: string, custom = true): Promise<void> {\n this.customPatterns.add(pattern);\n this.compiledCustomContexts.set(pattern, CTX_ALL);\n\n if (custom && this.redisHandler) {\n await this.redisHandler.setKey('patterns', 'custom', [...this.customPatterns].join(','));\n }\n }\n\n async removePattern(pattern: string): Promise<void> {\n this.customPatterns.delete(pattern);\n this.compiledCustomContexts.delete(pattern);\n\n if (this.redisHandler) {\n await this.redisHandler.setKey('patterns', 'custom', [...this.customPatterns].join(','));\n }\n\n await this.compiler.clearCache();\n await this.monitor.removePatternStats(pattern);\n }\n\n getDefaultPatterns(): string[] {\n return PATTERN_DEFINITIONS.map(([p]) => p);\n }\n\n getCustomPatterns(): string[] {\n return [...this.customPatterns];\n }\n\n getAllPatterns(): string[] {\n return [...this.getDefaultPatterns(), ...this.getCustomPatterns()];\n }\n\n async getPerformanceStats(): Promise<Record<string, unknown> | null> {\n return {\n summary: this.monitor.getSummaryStats(),\n slowPatterns: this.monitor.getSlowPatterns(),\n problematicPatterns: this.monitor.getProblematicPatterns(),\n };\n }\n\n getComponentStatus(): Record<string, boolean> {\n return {\n compiler: true,\n preprocessor: true,\n semanticAnalyzer: true,\n performanceMonitor: true,\n };\n }\n\n async configureSemanticThreshold(threshold: number): Promise<void> {\n this.semanticThreshold = Math.max(0, Math.min(1, threshold));\n }\n\n async reset(): Promise<void> {\n this.customPatterns.clear();\n this.compiledCustomContexts.clear();\n this.agentHandler = null;\n await this.compiler.clearCache();\n await this.monitor.clearStats();\n }\n}\n"],"mappings":"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","names":["remaining"]}
@@ -0,0 +1,132 @@
1
+ // src/handlers/cloud.ts
2
+ import * as ipaddr from "ipaddr.js";
3
+ var AWS_RANGES_URL = "https://ip-ranges.amazonaws.com/ip-ranges.json";
4
+ var GCP_RANGES_URL = "https://www.gstatic.com/ipranges/cloud.json";
5
+ var AZURE_DOWNLOAD_PAGE = "https://www.microsoft.com/en-us/download/details.aspx?id=56519";
6
+ var AZURE_JSON_HREF_RE = /href=["'](https:\/\/download\.microsoft\.com\/.{1,500}?\.json)["']/;
7
+ var CloudHandler = class {
8
+ constructor(logger) {
9
+ this.logger = logger;
10
+ }
11
+ ipRanges = /* @__PURE__ */ new Map();
12
+ lastUpdated = /* @__PURE__ */ new Map();
13
+ redisHandler = null;
14
+ agentHandler = null;
15
+ async initializeRedis(redisHandler, providers, ttl = 3600) {
16
+ this.redisHandler = redisHandler;
17
+ await this.refreshAsync(providers, ttl);
18
+ }
19
+ async initializeAgent(agentHandler) {
20
+ this.agentHandler = agentHandler;
21
+ }
22
+ async refreshAsync(providers, ttl = 3600) {
23
+ for (const provider of providers) {
24
+ try {
25
+ const ranges = await this.fetchProviderRanges(provider);
26
+ this.ipRanges.set(provider, ranges);
27
+ this.lastUpdated.set(provider, /* @__PURE__ */ new Date());
28
+ if (this.redisHandler) {
29
+ await this.redisHandler.setKey("cloud_ranges", provider, ranges.join(","), ttl);
30
+ }
31
+ this.logger.info(`Refreshed ${ranges.length} IP ranges for ${provider}`);
32
+ } catch (e) {
33
+ this.logger.error(`Failed to refresh ${provider} IP ranges: ${e}`);
34
+ if (this.redisHandler) {
35
+ const cached = await this.redisHandler.getKey("cloud_ranges", provider);
36
+ if (typeof cached === "string" && cached.length > 0) {
37
+ this.ipRanges.set(provider, cached.split(","));
38
+ this.logger.info(`Loaded ${provider} IP ranges from Redis cache`);
39
+ }
40
+ }
41
+ }
42
+ }
43
+ }
44
+ async fetchProviderRanges(provider) {
45
+ switch (provider) {
46
+ case "AWS":
47
+ return this.fetchAwsRanges();
48
+ case "GCP":
49
+ return this.fetchGcpRanges();
50
+ case "Azure":
51
+ return this.fetchAzureRanges();
52
+ default:
53
+ return [];
54
+ }
55
+ }
56
+ async fetchAwsRanges() {
57
+ const resp = await fetch(AWS_RANGES_URL);
58
+ const data = await resp.json();
59
+ return data.prefixes.filter((p) => p.service === "AMAZON").map((p) => p.ip_prefix);
60
+ }
61
+ async fetchGcpRanges() {
62
+ const resp = await fetch(GCP_RANGES_URL);
63
+ const data = await resp.json();
64
+ return data.prefixes.map((p) => p.ipv4Prefix ?? p.ipv6Prefix).filter((p) => p !== void 0);
65
+ }
66
+ async fetchAzureRanges() {
67
+ const pageResp = await fetch(AZURE_DOWNLOAD_PAGE);
68
+ const html = await pageResp.text();
69
+ const match = AZURE_JSON_HREF_RE.exec(html);
70
+ if (!match) {
71
+ this.logger.warn("Could not find Azure IP ranges download URL");
72
+ return [];
73
+ }
74
+ const jsonResp = await fetch(match[1]);
75
+ const data = await jsonResp.json();
76
+ return data.values.flatMap((v) => v.properties.addressPrefixes);
77
+ }
78
+ isCloudIp(ip, providers) {
79
+ try {
80
+ const parsed = ipaddr.parse(ip);
81
+ for (const provider of providers) {
82
+ const ranges = this.ipRanges.get(provider);
83
+ if (!ranges) continue;
84
+ for (const cidr of ranges) {
85
+ try {
86
+ const [addr, prefixLen] = ipaddr.parseCIDR(cidr);
87
+ if (parsed.kind() === addr.kind() && parsed.match([addr, prefixLen])) {
88
+ return true;
89
+ }
90
+ } catch {
91
+ continue;
92
+ }
93
+ }
94
+ }
95
+ } catch {
96
+ }
97
+ return false;
98
+ }
99
+ getCloudProviderDetails(ip, providers) {
100
+ try {
101
+ const parsed = ipaddr.parse(ip);
102
+ for (const provider of providers) {
103
+ const ranges = this.ipRanges.get(provider);
104
+ if (!ranges) continue;
105
+ for (const cidr of ranges) {
106
+ try {
107
+ const [addr, prefixLen] = ipaddr.parseCIDR(cidr);
108
+ if (parsed.kind() === addr.kind() && parsed.match([addr, prefixLen])) {
109
+ return [provider, cidr];
110
+ }
111
+ } catch {
112
+ continue;
113
+ }
114
+ }
115
+ }
116
+ } catch {
117
+ }
118
+ return null;
119
+ }
120
+ async reset() {
121
+ this.ipRanges.clear();
122
+ this.lastUpdated.clear();
123
+ if (this.redisHandler) {
124
+ await this.redisHandler.deletePattern("cloud_ranges:*");
125
+ }
126
+ }
127
+ };
128
+
129
+ export {
130
+ CloudHandler
131
+ };
132
+ //# sourceMappingURL=chunk-LK7N5CAQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/handlers/cloud.ts"],"sourcesContent":["import * as ipaddr from 'ipaddr.js';\n\nimport type { Logger } from '../models/logger.js';\nimport type { AgentHandlerProtocol } from '../protocols/agent.js';\nimport type { RedisManager } from './redis.js';\n\nconst AWS_RANGES_URL = 'https://ip-ranges.amazonaws.com/ip-ranges.json';\nconst GCP_RANGES_URL = 'https://www.gstatic.com/ipranges/cloud.json';\nconst AZURE_DOWNLOAD_PAGE = 'https://www.microsoft.com/en-us/download/details.aspx?id=56519';\nconst AZURE_JSON_HREF_RE = /href=[\"'](https:\\/\\/download\\.microsoft\\.com\\/.{1,500}?\\.json)[\"']/;\n\nexport class CloudHandler {\n private ipRanges = new Map<string, string[]>();\n private lastUpdated = new Map<string, Date | null>();\n private redisHandler: RedisManager | null = null;\n private agentHandler: AgentHandlerProtocol | null = null;\n\n constructor(private readonly logger: Logger) {}\n\n async initializeRedis(redisHandler: RedisManager, providers: Set<string>, ttl = 3600): Promise<void> {\n this.redisHandler = redisHandler;\n await this.refreshAsync(providers, ttl);\n }\n\n async initializeAgent(agentHandler: AgentHandlerProtocol): Promise<void> {\n this.agentHandler = agentHandler;\n }\n\n async refreshAsync(providers: Set<string>, ttl = 3600): Promise<void> {\n for (const provider of providers) {\n try {\n const ranges = await this.fetchProviderRanges(provider);\n this.ipRanges.set(provider, ranges);\n this.lastUpdated.set(provider, new Date());\n\n if (this.redisHandler) {\n await this.redisHandler.setKey('cloud_ranges', provider, ranges.join(','), ttl);\n }\n\n this.logger.info(`Refreshed ${ranges.length} IP ranges for ${provider}`);\n } catch (e) {\n this.logger.error(`Failed to refresh ${provider} IP ranges: ${e}`);\n\n if (this.redisHandler) {\n const cached = await this.redisHandler.getKey('cloud_ranges', provider);\n if (typeof cached === 'string' && cached.length > 0) {\n this.ipRanges.set(provider, cached.split(','));\n this.logger.info(`Loaded ${provider} IP ranges from Redis cache`);\n }\n }\n }\n }\n }\n\n private async fetchProviderRanges(provider: string): Promise<string[]> {\n switch (provider) {\n case 'AWS': return this.fetchAwsRanges();\n case 'GCP': return this.fetchGcpRanges();\n case 'Azure': return this.fetchAzureRanges();\n default: return [];\n }\n }\n\n private async fetchAwsRanges(): Promise<string[]> {\n const resp = await fetch(AWS_RANGES_URL);\n const data = await resp.json() as { prefixes: Array<{ ip_prefix: string; service: string }> };\n return data.prefixes\n .filter((p) => p.service === 'AMAZON')\n .map((p) => p.ip_prefix);\n }\n\n private async fetchGcpRanges(): Promise<string[]> {\n const resp = await fetch(GCP_RANGES_URL);\n const data = await resp.json() as { prefixes: Array<{ ipv4Prefix?: string; ipv6Prefix?: string }> };\n return data.prefixes\n .map((p) => p.ipv4Prefix ?? p.ipv6Prefix)\n .filter((p): p is string => p !== undefined);\n }\n\n private async fetchAzureRanges(): Promise<string[]> {\n const pageResp = await fetch(AZURE_DOWNLOAD_PAGE);\n const html = await pageResp.text();\n const match = AZURE_JSON_HREF_RE.exec(html);\n if (!match) {\n this.logger.warn('Could not find Azure IP ranges download URL');\n return [];\n }\n\n const jsonResp = await fetch(match[1]);\n const data = await jsonResp.json() as { values: Array<{ properties: { addressPrefixes: string[] } }> };\n return data.values.flatMap((v) => v.properties.addressPrefixes);\n }\n\n isCloudIp(ip: string, providers: Set<string>): boolean {\n try {\n const parsed = ipaddr.parse(ip);\n for (const provider of providers) {\n const ranges = this.ipRanges.get(provider);\n if (!ranges) continue;\n for (const cidr of ranges) {\n try {\n const [addr, prefixLen] = ipaddr.parseCIDR(cidr);\n if (parsed.kind() === addr.kind() && parsed.match([addr, prefixLen])) {\n return true;\n }\n } catch { continue; }\n }\n }\n } catch { /* invalid IP */ }\n return false;\n }\n\n getCloudProviderDetails(ip: string, providers: Set<string>): [string, string] | null {\n try {\n const parsed = ipaddr.parse(ip);\n for (const provider of providers) {\n const ranges = this.ipRanges.get(provider);\n if (!ranges) continue;\n for (const cidr of ranges) {\n try {\n const [addr, prefixLen] = ipaddr.parseCIDR(cidr);\n if (parsed.kind() === addr.kind() && parsed.match([addr, prefixLen])) {\n return [provider, cidr];\n }\n } catch { continue; }\n }\n /* v8 ignore start -- closing braces + outer catch for invalid IP; requires full agent integration */\n }\n } catch { /* invalid IP */ }\n /* v8 ignore stop */\n return null;\n }\n\n async reset(): Promise<void> {\n this.ipRanges.clear();\n this.lastUpdated.clear();\n /* v8 ignore start -- agent event dispatch in dynamic rule application; requires full agent integration */\n if (this.redisHandler) {\n await this.redisHandler.deletePattern('cloud_ranges:*');\n }\n /* v8 ignore stop */\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,8 @@
1
+ import {
2
+ CloudHandler
3
+ } from "./chunk-LK7N5CAQ.js";
4
+ import "./chunk-DGUM43GV.js";
5
+ export {
6
+ CloudHandler
7
+ };
8
+ //# sourceMappingURL=cloud-46J7XK7I.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}