aimless-security
Version:
Enhanced Runtime Application Self-Protection (RASP) and API Fuzzing Engine with advanced threat detection, behavioral analysis, and intelligent response scoring for Node.js applications
625 lines • 26.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.InjectionDetector = void 0;
const types_1 = require("../types");
class InjectionDetector {
constructor() {
// Unicode SQL Injection patterns (separate for high-confidence detection)
this.unicodeSQLPatterns = [
/[\uFF03-\uFF5E]/, // Full-width characters (e.g., SELECT)
/\u0053\u0045\u004C\u0045\u0043\u0054/i, // Unicode SELECT
/\u0055\u004E\u0049\u004F\u004E/i, // Unicode UNION
/\u0044\u0052\u004F\u0050/i, // Unicode DROP
// Homoglyph attacks (visually similar characters)
/[ЅЕLЕСТІОNUΝІОN]/, // Cyrillic lookalikes (Е is Cyrillic E)
/[ᏚᎬᏞᎬᏟᎢ]/, // Cherokee lookalikes
// Latin Extended ranges that could be used for obfuscation
/[\u0100-\u017F][\u0100-\u017F]+/, // Require 2+ Latin Extended-A chars
];
// Enhanced SQL Injection patterns with context awareness
this.sqlPatterns = [
// SQL Keywords - more comprehensive
/(\b(SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC|EXECUTE|UNION|DECLARE|TRUNCATE|MERGE|REPLACE)\b)/i,
// Tautology-based injections
/(\bOR\b\s+['"]?\w+['"]?\s*=\s*['"]?\w+['"]?)/i,
/(\bAND\b\s+['"]?\w+['"]?\s*=\s*['"]?\w+['"]?)/i,
/(\bOR\b\s+\d+\s*[=<>]+\s*\d+)/i,
/(\bAND\b\s+\d+\s*[=<>]+\s*\d+)/i,
// Classic tautologies
/'\s*OR\s*'1'\s*=\s*'1/i,
/"\s*OR\s*"1"\s*=\s*"1/i,
/'\s*OR\s*1\s*=\s*1/i,
/'\s*AND\s*'1'\s*=\s*'1/i,
// Admin bypass patterns
/admin'\s*(--|#|\/\*)/i,
/'\s*OR\s*'a'\s*=\s*'a/i,
// SQL comments and terminators
/(--|#|\/\*|\*\/|;)\s*$/,
/';?\s*(--|#)/,
// Union-based injections
/(\bUNION\b\s+(ALL\s+)?SELECT\b)/i,
/\bUNION\b.*\bSELECT\b/i,
// Quote manipulation
/('|")\s*(OR|AND)\s*('|")\s*=\s*('|")/i,
// Hex encoding
/(0x[0-9a-fA-F]{2,})/,
// SQL functions
/(\b(CHAR|CONCAT|SUBSTRING|ASCII|ORD|HEX|UNHEX|BENCHMARK|SLEEP|WAITFOR|DELAY|LOAD_FILE|INTO\s+OUTFILE)\b\s*\()/i,
// Stored procedures
/\b(xp_|sp_)\w+/i,
// Stacked queries
/;\s*(SELECT|INSERT|UPDATE|DELETE|DROP|CREATE)/i,
// Time-based blind injection
/\b(SLEEP|BENCHMARK|WAITFOR\s+DELAY|pg_sleep|DBMS_LOCK\.SLEEP)\b/i,
// Error-based injection
/\b(EXTRACTVALUE|UPDATEXML|EXP|POW|FLOOR|RAND|GROUP_CONCAT)\b\s*\(/i,
// Information schema access
/\b(information_schema|sys\.|mysql\.|performance_schema|pg_catalog)\b/i,
// Boolean-based blind
/\b(CASE|IF|IIF|CHOOSE)\b\s*\(/i,
// Database version fingerprinting
/\b(@@version|version\(\)|sqlite_version|pg_version)\b/i,
// Database user extraction
/\b(user\(\)|current_user|session_user|system_user)\b/i,
// NULL byte injection in SQL
/\x00/,
// SQL wildcards in suspicious contexts
/[%_]\s*['"]?\s*(OR|AND)\s*['"]?/i,
// Multi-line comment injection
/\/\*.*?\*\//s
];
// Enhanced NoSQL Injection patterns
this.nosqlPatterns = [
// MongoDB operators
/\$where/i,
/\$(ne|eq|gt|gte|lt|lte|in|nin|regex|exists|type|mod|text|all|elemMatch|size|slice)/i,
// Object notation
/\{\s*['"]\$[a-z]+['"]\s*:/i,
// JavaScript injection in MongoDB
/\bthis\b\s*\.\s*\w+/,
/\bfunction\s*\(/,
/\beval\s*\(/,
/constructor\s*\(/i,
// NoSQL aggregation
/\$(match|group|project|lookup|unwind|sort|limit|skip|count|addFields|replaceRoot)/i,
// CouchDB/PouchDB
/_design\//,
/_view\//,
/_all_docs/i,
// Redis commands
/\b(FLUSHALL|FLUSHDB|CONFIG|EVAL|SCRIPT|KEYS|DEL|SET|GET|APPEND)\b/i,
// Cassandra CQL
/\b(ALLOW\s+FILTERING|BATCH|TRUNCATE)\b/i,
// NoSQL injection via array
/\[\s*\{\s*['"]\$/,
// MongoDB mapReduce injection
/\b(mapReduce|map|reduce|finalize)\b/i,
// Prototype pollution
/__proto__/,
/constructor\.prototype/i,
// Server-side JavaScript
/process\./,
/require\s*\(/,
/global\./,
// MongoDB $function operator
/\$function/i
];
// Enhanced Command Injection patterns
this.commandPatterns = [
// Command separators and operators
/[;&|`$(){}[\]<>]/,
/(\|\||&&)/,
// Common Unix/Linux commands
/\b(cat|ls|dir|pwd|cd|echo|printf|ping|whoami|id|uname|wget|curl|nc|netcat|ncat|bash|sh|zsh|csh|ksh|find|grep|awk|sed|chmod|chown|kill|ps|top|df|du|mount|umount|dd)\b/i,
// Common Windows commands
/\b(cmd|powershell|pwsh|wmic|reg|sc|net|tasklist|taskkill|ipconfig|systeminfo|type|copy|move|del|rd|mkdir)\b/i,
// Path traversal in commands
/(\.\.[\/\\]|~\/)/,
// Newline injections
/(\r\n|\n|\r|%0a|%0d)/,
// Backticks and command substitution
/`[^`]*`/,
/\$\([^)]*\)/,
// PowerShell specific
/\b(Invoke-Expression|IEX|Invoke-Command|ICM|Get-Content|GC|Start-Process|Stop-Process|Get-Process)\b/i,
// File redirection
/[><]{1,2}\s*[\/\w.]/,
// Environment variables
/\$\{?\w+\}?/,
/%\w+%/,
// Null byte injection
/\x00|%00/,
// SSH and network commands
/\b(ssh|scp|sftp|telnet|ftp|tftp|rsync)\b/i,
// File manipulation
/\b(tar|gzip|gunzip|zip|unzip|bzip2|7z|rar)\b/i,
// Process control
/\b(nohup|screen|tmux|disown|jobs|fg|bg)\b/i,
// Package managers
/\b(apt|apt-get|yum|dnf|pacman|brew|npm|pip|gem|cargo)\b/i,
// Text editors (can be used for file manipulation)
/\b(vi|vim|nano|emacs|pico)\b/i,
// Reverse shells
/\b(socat|perl|python|ruby|php|node)\b.*-e/i,
// Base64 encoded commands
/base64.*-d/i,
// Compression and archiving with command execution
/\|\s*(sh|bash|zsh|ksh|csh)/i
];
// Enhanced Path Traversal patterns
this.pathTraversalPatterns = [
// Standard traversal
/\.\.[\/\\]/,
/\.\.[\/\\]\.\.[\/\\]/,
// URL encoded
/%2e%2e[\/\\]/i,
/%252e%252e[\/\\]/i, // Double encoded
/%c0%ae%c0%ae[\/\\]/i, // Overlong UTF-8
/\.\.[%]{2}[f5c][\/\\]/i,
// Unicode variations
/\u002e\u002e[\/\\]/,
/\uff0e\uff0e[\/\\]/,
// Sensitive paths
/(\/|\\)(etc|windows|system32|boot|proc|sys|var|usr|opt|home|root)/i,
// Windows drive letters
/[a-zA-Z]:[\/\\]/,
// Null bytes
/\0|%00/,
// UNC paths
/\\\\[^\\]+\\/,
// Absolute paths
/^\/[a-z]/i,
// Multiple slashes
/[\/\\]{2,}/
];
// Enhanced XXE patterns
this.xxePatterns = [
// Entity declarations
/<!ENTITY/i,
/<!DOCTYPE/i,
// External references
/SYSTEM\s+["']/i,
/PUBLIC\s+["']/i,
// Parameter entities
/%\w+;/,
// External DTD
/<!ELEMENT/i,
/<!ATTLIST/i,
// Common XXE payloads
/file:\/\//i,
/php:\/\//i,
/expect:\/\//i,
/data:\/\//i,
// XML processing instructions
/<\?xml[^>]*>/i,
// XSLT attacks
/<xsl:/i
];
// Enhanced SSRF patterns
this.ssrfPatterns = [
// Localhost variations
/localhost/i,
/127\.0\.0\.1/,
/0\.0\.0\.0/,
/0x7f\.0\.0\.1/,
/0x7f000001/,
/2130706433/, // Decimal representation of 127.0.0.1
/017700000001/, // Octal
// IPv6 localhost
/::1/,
/::ffff:127\.0\.0\.1/,
/0:0:0:0:0:0:0:1/,
// Link-local
/169\.254\./,
/fe80:/i,
// Private IP ranges
/192\.168\./,
/10\./,
/172\.(1[6-9]|2[0-9]|3[0-1])\./,
// Cloud metadata endpoints
/169\.254\.169\.254/,
/metadata\.google\.internal/i,
/metadata\.azure/i,
// URL credentials
/@/,
// DNS rebinding
/\d+\.\d+\.\d+\.\d+\.xip\.io/i,
/\d+\.\d+\.\d+\.\d+\.nip\.io/i,
// URL encoding tricks
/%32%35%35/i,
// File protocols
/file:\/\//i,
/gopher:\/\//i,
/dict:\/\//i,
/ftp:\/\//i,
/tftp:\/\//i
];
// Whitelist for legitimate inputs to reduce false positives
this.whitelistPatterns = [
// Common safe patterns
/^[a-zA-Z0-9_@.-]+$/,
// Email addresses
/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
// UUIDs
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,
// ISO dates
/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?)?$/,
// Simple numbers
/^\d+$/,
/^\d+\.\d+$/,
// Common safe strings (alphanumeric with spaces)
/^[a-zA-Z0-9\s]+$/
];
// Context-specific safe patterns
this.contextWhitelist = {
email: [/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/],
username: [/^[a-zA-Z0-9_.-]{3,30}$/],
name: [/^[a-zA-Z\s'-]{1,50}$/],
uuid: [/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i],
date: [/^\d{4}-\d{2}-\d{2}$/],
url: [/^https?:\/\/[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/],
number: [/^\d+$/, /^\d+\.\d+$/],
alphanumeric: [/^[a-zA-Z0-9]+$/]
};
}
detect(input, context = 'unknown') {
const threats = [];
if (!input)
return threats;
const inputs = this.extractInputs(input);
for (const value of inputs) {
if (typeof value !== 'string')
continue;
// Skip very short or very long inputs (likely false positives or DOS attempts)
if (value.length < 2 || value.length > 10000)
continue;
// Skip if value matches whitelist (reduce false positives)
if (this.isWhitelisted(value, context))
continue;
// Skip common safe values
if (this.isSafeValue(value))
continue;
// SQL Injection detection with confidence scoring
const sqlMatches = this.sqlPatterns.filter(pattern => pattern.test(value));
const unicodeMatches = this.unicodeSQLPatterns.filter(pattern => pattern.test(value));
const totalSQLMatches = sqlMatches.length + unicodeMatches.length;
const isHighConfidence = this.hasHighConfidenceSQLPattern(value);
// Check if we should block - high confidence patterns OR multiple matches OR unicode
if (totalSQLMatches > 0 || isHighConfidence) {
// Unicode SQL patterns are ALWAYS high confidence - even 1 match is suspicious
// Regular SQL patterns need 2+ matches UNLESS they're high confidence
const shouldBlock = unicodeMatches.length > 0 || totalSQLMatches >= 2 || isHighConfidence;
if (shouldBlock) {
const attackType = unicodeMatches.length > 0 ? 'unicode-sql' : 'sql';
const confidence = unicodeMatches.length > 0 ?
Math.max(85, this.calculateConfidenceNumber(totalSQLMatches, this.sqlPatterns.length)) : // Unicode is always high confidence
this.calculateConfidenceNumber(totalSQLMatches, this.sqlPatterns.length);
threats.push({
type: types_1.ThreatType.SQL_INJECTION,
severity: unicodeMatches.length > 0 || totalSQLMatches >= 3 ? 'critical' : 'high',
description: `Potential ${unicodeMatches.length > 0 ? 'Unicode ' : ''}SQL injection detected (confidence: ${unicodeMatches.length > 0 ? confidence : this.calculateConfidence(totalSQLMatches, this.sqlPatterns.length)}%)`,
payload: value,
timestamp: new Date(),
blocked: true,
confidence,
metadata: {
context,
matchCount: totalSQLMatches,
attackType,
unicodeDetected: unicodeMatches.length > 0,
confidence: `${confidence}%`
}
});
}
}
// NoSQL Injection detection with confidence scoring
const nosqlMatches = this.nosqlPatterns.filter(pattern => pattern.test(value));
if (nosqlMatches.length >= 2 || this.hasHighConfidenceNoSQLPattern(value)) {
threats.push({
type: types_1.ThreatType.NOSQL_INJECTION,
severity: nosqlMatches.length >= 3 ? 'critical' : 'high',
description: `Potential NoSQL injection detected (confidence: ${this.calculateConfidence(nosqlMatches.length, this.nosqlPatterns.length)})`,
payload: value,
timestamp: new Date(),
blocked: true,
confidence: this.calculateConfidenceNumber(nosqlMatches.length, this.nosqlPatterns.length),
metadata: {
context,
matchCount: nosqlMatches.length,
confidence: this.calculateConfidence(nosqlMatches.length, this.nosqlPatterns.length)
}
});
}
// Command Injection detection with confidence scoring
const cmdMatches = this.commandPatterns.filter(pattern => pattern.test(value));
if (cmdMatches.length >= 2 || this.hasHighConfidenceCommandPattern(value)) {
threats.push({
type: types_1.ThreatType.COMMAND_INJECTION,
severity: 'critical',
description: `Potential command injection detected (confidence: ${this.calculateConfidence(cmdMatches.length, this.commandPatterns.length)})`,
payload: value,
timestamp: new Date(),
blocked: true,
confidence: this.calculateConfidenceNumber(cmdMatches.length, this.commandPatterns.length),
metadata: {
context,
matchCount: cmdMatches.length,
confidence: this.calculateConfidence(cmdMatches.length, this.commandPatterns.length)
}
});
}
// Path Traversal detection with confidence scoring
const pathMatches = this.pathTraversalPatterns.filter(pattern => pattern.test(value));
if (pathMatches.length > 0) {
threats.push({
type: types_1.ThreatType.PATH_TRAVERSAL,
severity: pathMatches.length >= 2 ? 'critical' : 'high',
description: `Potential path traversal detected (confidence: ${this.calculateConfidence(pathMatches.length, this.pathTraversalPatterns.length)})`,
payload: value,
timestamp: new Date(),
blocked: true,
metadata: {
context,
matchCount: pathMatches.length,
confidence: this.calculateConfidence(pathMatches.length, this.pathTraversalPatterns.length)
}
});
}
// XXE detection with confidence scoring
const xxeMatches = this.xxePatterns.filter(pattern => pattern.test(value));
if (xxeMatches.length > 0) {
threats.push({
type: types_1.ThreatType.XXE,
severity: xxeMatches.length >= 2 ? 'critical' : 'high',
description: `Potential XXE attack detected (confidence: ${this.calculateConfidence(xxeMatches.length, this.xxePatterns.length)})`,
payload: value,
timestamp: new Date(),
blocked: true,
metadata: {
context,
matchCount: xxeMatches.length,
confidence: this.calculateConfidence(xxeMatches.length, this.xxePatterns.length)
}
});
}
// SSRF detection with confidence scoring
const ssrfMatches = this.ssrfPatterns.filter(pattern => pattern.test(value));
if (ssrfMatches.length > 0) {
threats.push({
type: types_1.ThreatType.SSRF,
severity: ssrfMatches.length >= 2 ? 'high' : 'medium',
description: `Potential SSRF attack detected (confidence: ${this.calculateConfidence(ssrfMatches.length, this.ssrfPatterns.length)})`,
payload: value,
timestamp: new Date(),
blocked: true,
metadata: {
context,
matchCount: ssrfMatches.length,
confidence: this.calculateConfidence(ssrfMatches.length, this.ssrfPatterns.length)
}
});
}
// Polyglot Injection detection (SQL + XSS combined)
const polyglotThreat = this.detectPolyglot(value);
if (polyglotThreat) {
threats.push(polyglotThreat);
}
}
return threats;
}
/**
* Detect polyglot injections (SQL + XSS combined attacks)
* These are sophisticated attacks that work as both SQL and XSS
*/
detectPolyglot(value) {
// Polyglot patterns - attacks that work as both SQL and XSS
const polyglotPatterns = [
// Classic polyglot: works as SQL injection AND XSS
/'><script>.*?<\/script>/i,
/'\s*OR\s*.*?<script>/i,
/"\s*OR\s*.*?<script>/i,
// SQL with XSS payload
/'\s*UNION.*?<script>/i,
/SELECT.*?<script>/i,
// XSS with SQL syntax
/<script>.*?(SELECT|UNION|INSERT|DELETE)/i,
/<img.*?(SELECT|UNION|OR\s*1=1)/i,
// JavaScript protocol with SQL
/javascript:.*?(SELECT|UNION|INSERT)/i,
// Event handlers with SQL
/on\w+\s*=.*?(SELECT|UNION|OR\s*['"]?\d+['"]?\s*=\s*['"]?\d+)/i,
// Data URI with SQL
/data:text\/html.*?(SELECT|UNION|INSERT)/i,
// SVG with SQL injection
/<svg.*?(SELECT|UNION|INSERT)/i,
// SQL comments with HTML tags
/<!--.*?(SELECT|UNION|INSERT).*?-->/i,
// Combined quote escaping
/['"].*?<.*?>.*?(OR|UNION|SELECT)/i,
// CDATA sections with SQL
/<!\[CDATA\[.*?(SELECT|UNION|INSERT)/i,
// Attribute injection with SQL
/\w+\s*=\s*['"].*?(SELECT|UNION).*?<\//i
];
const matches = polyglotPatterns.filter(pattern => pattern.test(value));
if (matches.length >= 2) {
return {
type: types_1.ThreatType.SQL_INJECTION, // Could be either, using SQL as primary
severity: 'critical',
description: `Polyglot injection detected (SQL + XSS combined attack) - confidence: ${this.calculateConfidence(matches.length, polyglotPatterns.length)}`,
payload: value,
timestamp: new Date(),
blocked: true,
confidence: this.calculateConfidenceNumber(matches.length, polyglotPatterns.length),
metadata: {
attackType: 'polyglot',
matchCount: matches.length,
confidence: this.calculateConfidence(matches.length, polyglotPatterns.length),
details: 'This payload can exploit both SQL injection and XSS vulnerabilities'
}
};
}
return null;
}
extractInputs(input) {
const inputs = [];
if (typeof input === 'string') {
inputs.push(input);
}
else if (Array.isArray(input)) {
for (const item of input) {
inputs.push(...this.extractInputs(item));
}
}
else if (typeof input === 'object' && input !== null) {
for (const key in input) {
inputs.push(key);
inputs.push(...this.extractInputs(input[key]));
}
}
return inputs;
}
/**
* Calculate confidence score (0-100) based on pattern matches
*/
calculateConfidence(matches, totalPatterns) {
// More realistic confidence calculation
// 1 match = 30%, 2 matches = 60%, 3+ matches = 90%+
let percentage;
if (matches === 1) {
percentage = 30;
}
else if (matches === 2) {
percentage = 60;
}
else if (matches === 3) {
percentage = 85;
}
else {
percentage = Math.min(85 + (matches - 3) * 5, 100);
}
return `${Math.round(percentage)}%`;
}
/**
* Calculate numeric confidence score (0-100)
*/
calculateConfidenceNumber(matches, totalPatterns) {
if (matches === 1) {
return 30;
}
else if (matches === 2) {
return 60;
}
else if (matches === 3) {
return 85;
}
else {
return Math.min(85 + (matches - 3) * 5, 100);
}
}
/**
* Check if value contains high-confidence SQL injection patterns
*/
hasHighConfidenceSQLPattern(value) {
// These patterns are almost always malicious
const highConfidencePatterns = [
/'\s*OR\s*'1'\s*=\s*'1/i,
/'\s*OR\s*1\s*=\s*1/i,
/\bUNION\b.*\bSELECT\b/i,
/admin'\s*(--|#)/i,
/;\s*DROP\s+/i,
/;\s*DELETE\s+FROM\s+/i,
/\bEXEC\s*\(/i,
/\bEXECUTE\s*\(/i,
// Single quote at end of word is highly suspicious (e.g., "admin'")
/\w+'\s*$/,
// Single quote followed by SQL keywords
/'\s*(OR|AND|UNION|SELECT|WHERE|FROM|DROP|INSERT|UPDATE|DELETE)\b/i,
// Single quote followed by comment markers
/'\s*(--|#|\/\*)/
];
return highConfidencePatterns.some(pattern => pattern.test(value));
}
/**
* Check if value contains high-confidence NoSQL injection patterns
*/
hasHighConfidenceNoSQLPattern(value) {
const highConfidencePatterns = [
/\$where.*function/i,
/__proto__/,
/constructor\.prototype/i,
/\{\s*['"]\$ne['"]\s*:\s*null\s*\}/i,
/process\./,
/require\s*\(/
];
return highConfidencePatterns.some(pattern => pattern.test(value));
}
/**
* Check if value contains high-confidence command injection patterns
*/
hasHighConfidenceCommandPattern(value) {
const highConfidencePatterns = [
/;\s*(rm|del|format|dd)\s+/i,
/\|\s*(sh|bash|cmd|powershell)\s*$/i,
/`.*\|/,
/\$\(.*\|/,
/wget.*\|/i,
/curl.*\|/i,
/nc\s+-e/i,
/bash\s+-i/i
];
return highConfidencePatterns.some(pattern => pattern.test(value));
}
/**
* Check if value is a common safe value that shouldn't trigger alerts
*/
isSafeValue(value) {
// Empty or whitespace only
if (!value || /^\s*$/.test(value))
return true;
// Check against whitelist patterns
if (this.whitelistPatterns.some(pattern => pattern.test(value)))
return true;
// Common safe words that might contain SQL keywords in normal text
const safeWords = [
'select',
'insert',
'update',
'delete',
'order',
'sort',
'filter',
'search',
'find'
];
// If it's just a single safe word, allow it
const lowerValue = value.toLowerCase().trim();
if (safeWords.includes(lowerValue))
return true;
// Check for normal prose (lots of spaces, proper capitalization)
const wordCount = value.split(/\s+/).length;
const hasProperSpacing = wordCount > 3 && /[a-zA-Z]\s+[a-zA-Z]/.test(value);
const noSuspiciousChars = !/[;'"<>{}$|&`]/.test(value);
if (hasProperSpacing && noSuspiciousChars)
return true;
return false;
}
/**
* Check if value matches whitelist patterns to reduce false positives
*/
isWhitelisted(value, context) {
// Check context-specific whitelist
if (this.contextWhitelist[context]) {
if (this.contextWhitelist[context].some(pattern => pattern.test(value))) {
return true;
}
}
// Check general whitelist
if (this.whitelistPatterns.some(pattern => pattern.test(value))) {
return true;
}
return false;
}
}
exports.InjectionDetector = InjectionDetector;
//# sourceMappingURL=injection-detector.js.map