{"version":3,"sources":["../../src/data/patterns.json","../../src/core/patterns-loader.ts","../../src/core/constants.ts","../../src/logging/redactor.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["{\n  \"version\": \"1.1.0\",\n  \"description\": \"Arcis Core Security Patterns - Language Agnostic\",\n  \"_pattern_convention\": {\n    \"description\": \"Pattern field naming convention for SDK implementers\",\n    \"pattern\": \"The primary regex pattern. May contain ReDoS-vulnerable constructs.\",\n    \"pattern_safe\": \"ReDoS-safe alternative pattern. SDKs MUST prefer this when available.\",\n    \"redos_safe\": \"Boolean indicating if 'pattern' is ReDoS-safe. If false, use 'pattern_safe'.\",\n    \"usage\": \"pattern_str = rule.get('pattern_safe') or rule.get('pattern')\"\n  },\n  \"config\": {\n    \"max_input_size\": 1000000,\n    \"max_recursion_depth\": 10,\n    \"enable_redos_protection\": true\n  },\n  \"patterns\": {\n    \"xss\": {\n      \"name\": \"Cross-Site Scripting (XSS)\",\n      \"severity\": \"critical\",\n      \"owasp\": \"A03:2021\",\n      \"rules\": [\n        {\n          \"id\": \"xss-script-block\",\n          \"pattern\": \"<script[^>]*>[\\\\s\\\\S]*?</script>\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects full script blocks (open tag through close tag)\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xss-script-tag\",\n          \"pattern\": \"<script[^>]*>\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects standalone or unclosed script tags\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xss-javascript-protocol\",\n          \"pattern\": \"javascript\\\\s*:[^\\\\s]\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects javascript: protocol (allows whitespace around colon)\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xss-event-handler-quoted\",\n          \"pattern\": \"(?:[\\\\s/])on\\\\w+\\\\s*=\\\\s*[\\\"'][^\\\"']*[\\\"']\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects inline event handlers with quoted values (e.g. onclick=\\\"alert(1)\\\")\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xss-event-handler-unquoted\",\n          \"pattern\": \"(?:[\\\\s/])on\\\\w+\\\\s*=\\\\s*[^\\\\s>]*\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects inline event handlers with unquoted values (e.g. onload=value)\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xss-iframe-block\",\n          \"pattern\": \"<iframe[^>]*>[\\\\s\\\\S]*?</iframe>\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects full iframe blocks\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xss-iframe\",\n          \"pattern\": \"<iframe[^>]*\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects iframe tags (partial or unclosed)\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xss-style-block\",\n          \"pattern\": \"<style[^>]*>[\\\\s\\\\S]*?</style>\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects full style blocks (CSS injection, expression(), behavior: attacks)\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xss-style-tag\",\n          \"pattern\": \"<style[\\\\s>][^>]*\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects style tags (partial or unclosed). Requires whitespace or > after `style` so `<styled>` / `<StyledButton>` text is not flagged.\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xss-object-block\",\n          \"pattern\": \"<object[^>]*>[\\\\s\\\\S]*?</object>\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects full object blocks\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xss-object\",\n          \"pattern\": \"<object[^>]*\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects object tags (partial or unclosed)\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xss-embed\",\n          \"pattern\": \"<embed[^>]*\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects embed tags\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xss-data-uri\",\n          \"pattern\": \"data\\\\s*:\\\\s*(?:text/html|image/svg)[^>\\\\s]*\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects data: URIs with HTML or SVG content (avoids 'metadata' false positives)\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xss-vbscript\",\n          \"pattern\": \"vbscript\\\\s*:\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects vbscript: protocol\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xss-url-encoded\",\n          \"pattern\": \"%3Cscript\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects URL-encoded script tags\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xss-svg-onload\",\n          \"pattern\": \"<svg[^>]*onload[^>]*>\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects SVG with inline event handlers\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xss-form-injection\",\n          \"pattern\": \"<form[\\\\s>][^>]*\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects form tags used for phishing/credential harvesting via action= redirection\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xss-meta-injection\",\n          \"pattern\": \"<meta[\\\\s>][^>]*\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects meta tags used for http-equiv refresh redirects or CSP bypass\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xss-base-injection\",\n          \"pattern\": \"<base[\\\\s>][^>]*\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects base href hijacking — redirects all relative URLs to attacker domain\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xss-link-injection\",\n          \"pattern\": \"<link[\\\\s>][^>]*\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects link tag injection used for stylesheet or preload CSRF attacks\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xss-css-expression\",\n          \"pattern\": \"expression\\\\s*\\\\(\",\n          \"flags\": \"gi\",\n          \"description\": \"Legacy IE CSS expression() in a style context, executes JS. Benchmark xss-style-expression.\",\n          \"redos_safe\": true\n        }\n      ],\n      \"encoding\": {\n        \"&\": \"&amp;\",\n        \"<\": \"&lt;\",\n        \">\": \"&gt;\",\n        \"\\\"\": \"&quot;\",\n        \"'\": \"&#x27;\"\n      }\n    },\n    \"sql_injection\": {\n      \"name\": \"SQL Injection\",\n      \"severity\": \"critical\",\n      \"owasp\": \"A03:2021\",\n      \"rules\": [\n        {\n          \"id\": \"sqli-keywords\",\n          \"pattern\": \"(\\\\bUNION\\\\s+(?:ALL\\\\s+)?SELECT\\\\b)|(\\\\b(?:DROP|TRUNCATE)\\\\s+(?:TABLE|DATABASE|INDEX|VIEW|SCHEMA)\\\\b)|(\\\\bINTO\\\\s+(?:OUTFILE|DUMPFILE)\\\\b)|(\\\\bATTACH\\\\s+DATABASE\\\\b)|(\\\\bCREATE\\\\s+(?:USER|FUNCTION|TRIGGER|PROCEDURE)\\\\b)|(\\\\bGRANT\\\\s+(?:ALL|SELECT|INSERT|UPDATE|DELETE)\\\\b)|(\\\\bSHUTDOWN\\\\b)|(\\\\bxp_cmdshell\\\\b)|(\\\\bsp_executesql\\\\b)\",\n          \"flags\": \"gi\",\n          \"description\": \"Multi-token SQL attack shapes (UNION SELECT, DROP TABLE, INTO OUTFILE, etc.) that real attackers use and benign users essentially never type. Replaces older bare-keyword rule that false-positived on 'please select an option', 'I'll update you tomorrow'. Benchmark FP class B3, 2026-06-07.\",\n          \"redos_safe\": true,\n          \"request_boundary_safe\": true\n        },\n        {\n          \"id\": \"sqli-comments\",\n          \"pattern\": \"((?:^|[^!])--(?:[\\\\s-]|$)|/\\\\*|\\\\*/)\",\n          \"flags\": \"g\",\n          \"description\": \"SQL comments. ANSI -- requires a following space / dash / end-of-string so it matches a real trailing comment (1=1--, -- -) but not CLI flags (--max-retries). C-style /* */ kept. MySQL # excluded (see sqli-comment-quote). FPR pass 2026-06-08. The -- must not be immediately preceded by '!' so HTML comments (<!-- -->) are not flagged as SQL.\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"sqli-boolean-numeric\",\n          \"pattern\": \"\\\\bOR\\\\s+\\\\d+\\\\s*=\\\\s*\\\\d+\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects OR 1=1 style injection\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"sqli-boolean-string\",\n          \"pattern\": \"\\\\bOR\\\\s+['\\\"][^'\\\"]*['\\\"]\\\\s*=\\\\s*['\\\"][^'\\\"]*['\\\"]?\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects OR 'a'='a' style injection\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"sqli-and-numeric\",\n          \"pattern\": \"\\\\bAND\\\\s+\\\\d+\\\\s*=\\\\s*\\\\d+\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects AND 1=1 style injection\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"sqli-and-string\",\n          \"pattern\": \"\\\\bAND\\\\s+['\\\"][^'\\\"]*['\\\"]\\\\s*=\\\\s*['\\\"][^'\\\"]*['\\\"]?\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects AND 'a'='a' style injection\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"sqli-sleep\",\n          \"pattern\": \"\\\\bSLEEP\\\\s*\\\\(\\\\s*\\\\d+\\\\s*\\\\)\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects time-based blind SQLi via SLEEP\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"sqli-benchmark\",\n          \"pattern\": \"\\\\bBENCHMARK\\\\s*\\\\(\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects time-based blind SQLi via BENCHMARK\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"sqli-pg-sleep\",\n          \"pattern\": \"\\\\bpg_sleep\\\\s*\\\\(\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects time-based blind SQLi via PostgreSQL pg_sleep\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"sqli-waitfor-delay\",\n          \"pattern\": \"\\\\bWAITFOR\\\\s+DELAY\\\\b\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects time-based blind SQLi via MSSQL WAITFOR DELAY\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"sqli-oracle-dbms-packages\",\n          \"pattern\": \"\\\\bDBMS_(?:LOCK|PIPE|UTILITY|XSLPROCESSOR|JAVA|OUTPUT|SCHEDULER)\\\\b\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects Oracle DBMS_* package references used in time-based blind SQLi (DBMS_LOCK.SLEEP, DBMS_PIPE.RECEIVE_MESSAGE) and other Oracle stdlib abuse paths. Broad match — no legitimate user input contains these (improvements.md §1.1.e Q3).\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"sqli-hex-blob\",\n          \"pattern\": \"\\\\b0x[0-9a-fA-F]{16,}\\\\b\",\n          \"flags\": \"gi\",\n          \"description\": \"Long hex-encoded blob (8+ bytes) smuggling SQL past keyword filters; far longer than any hex color. Benchmark sql-hex-encoded.\",\n          \"redos_safe\": true,\n          \"request_boundary_safe\": true\n        },\n        {\n          \"id\": \"sqli-comment-quote\",\n          \"pattern\": \"'\\\\s*#\",\n          \"flags\": \"g\",\n          \"description\": \"Single-quote immediately followed by a MySQL # line comment (admin' #). Quote anchor avoids FP on bare # (hex colors, hashtags). Benchmark sql-comment-hash.\",\n          \"redos_safe\": true,\n          \"request_boundary_safe\": true\n        }\n      ]\n    },\n    \"nosql_injection\": {\n      \"name\": \"NoSQL Injection\",\n      \"severity\": \"critical\",\n      \"owasp\": \"A03:2021\",\n      \"rules\": [\n        {\n          \"id\": \"nosql-operators\",\n          \"pattern\": \"\\\\$(?:gt|gte|lt|lte|ne|eq|in|nin|and|or|not|nor|exists|type|regex|where|expr|mod|text|jsonSchema|function|accumulator|elemMatch|all|size|lookup|match|project|group|sort|limit|skip|unwind|addFields|replaceRoot)\\\\b\",\n          \"flags\": \"i\",\n          \"description\": \"Detects MongoDB operators\",\n          \"redos_safe\": true\n        }\n      ],\n      \"dangerous_keys\": [\n        \"$gt\",\n        \"$gte\",\n        \"$lt\",\n        \"$lte\",\n        \"$ne\",\n        \"$eq\",\n        \"$in\",\n        \"$nin\",\n        \"$and\",\n        \"$or\",\n        \"$not\",\n        \"$nor\",\n        \"$exists\",\n        \"$type\",\n        \"$regex\",\n        \"$where\",\n        \"$expr\",\n        \"$mod\",\n        \"$text\",\n        \"$jsonSchema\",\n        \"$function\",\n        \"$accumulator\",\n        \"$elemMatch\",\n        \"$all\",\n        \"$size\",\n        \"$lookup\",\n        \"$match\",\n        \"$project\",\n        \"$group\",\n        \"$sort\",\n        \"$limit\",\n        \"$skip\",\n        \"$unwind\",\n        \"$addFields\",\n        \"$replaceRoot\"\n      ]\n    },\n    \"command_injection\": {\n      \"name\": \"Command Injection\",\n      \"severity\": \"critical\",\n      \"owasp\": \"A03:2021\",\n      \"rules\": [\n        {\n          \"id\": \"cmdi-shell-chars\",\n          \"pattern\": \"[;&|]\\\\s*(?:(?:cat|ls|dir|rm|cp|mv|wget|curl|nc|ncat|bash|sh|zsh|ksh|chmod|chown|kill|ps|id|touch|ping|dig|su|head|tail|php|sed|whoami|nslookup|nmap|python3?|perl|ruby|node|eval|exec|sudo|telnet|ssh|ftp|tftp|scp|awk|xxd)\\\\b|base64(?:\\\\s|$))\",\n          \"flags\": \"g\",\n          \"description\": \"Shell command chained after a metacharacter (; cat, | nc, & curl). Replaces the bare [;&|`] rule, which flagged every semicolon / ampersand in code, URLs and prose. FPR pass 2026-06-08. base64 requires a trailing space or end-of-input so `;base64 -d` is caught but the data-URI `;base64,` MIME parameter is not (FP on inline images).\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"cmdi-command-substitution\",\n          \"pattern\": \"\\\\$\\\\(\",\n          \"flags\": \"g\",\n          \"description\": \"Detects command substitution syntax $( — paired form, fewer false positives than bare parens\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"cmdi-ifs-bypass\",\n          \"pattern\": \"\\\\$\\\\{IFS(?:%[^}]*)?\\\\}\",\n          \"flags\": \"g\",\n          \"description\": \"Detects POSIX shell IFS substitution like ${IFS} or ${IFS%??}. Attackers use this to inject spaces past metacharacter filters in commands like `;cat${IFS}/etc/passwd` (improvements.md §1.1.e Q5).\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"cmdi-control-chars\",\n          \"pattern\": \"%0[0-9a-fA-F]\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects URL-encoded control characters (%00-%0F) including null, tab, vertical tab, form feed, LF, CR\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"cmdi-redirection\",\n          \"pattern\": \"(>>|<<<?)\",\n          \"flags\": \"g\",\n          \"description\": \"Append (>>) and here-doc (<<, <<<) redirection. The bare [<>] space form was dropped (matched 'a > b', 'RAM > 16GB'); redirect-to-file is covered by cmdi-redirect-syspath. FPR pass 2026-06-08.\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"cmdi-env-assign\",\n          \"pattern\": \"\\\\b(?:LD_PRELOAD|LD_LIBRARY_PATH|BASH_ENV|PYTHONPATH|PERL5LIB|DYLD_INSERT_LIBRARIES)\\\\s*=\",\n          \"flags\": \"gi\",\n          \"description\": \"Dangerous env-var assignment to smuggle code into a spawned process (LD_PRELOAD=). Benchmark cmd-env-var-smuggling.\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"cmdi-redirect-syspath\",\n          \"pattern\": \">\\\\s*/(?:etc|var|tmp|usr|bin|sbin|root|home|dev|proc|opt)\\\\b\",\n          \"flags\": \"g\",\n          \"description\": \"Shell output redirect to a system directory (> /var/www/shell.php). Anchored to system dirs to avoid math/text FP. Benchmark cmd-redirect-overwrite.\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"cmdi-newline-command\",\n          \"pattern\": \"[\\\\n\\\\r]\\\\s*(?:cat|ls|dir|rm|cp|mv|wget|curl|nc|ncat|bash|sh|zsh|ksh|chmod|chown|kill|ps|id|touch|ping|dig|su|head|tail|php|sed|whoami|nslookup|nmap|python3?|perl|ruby|node|eval|exec|sudo|telnet|ssh|ftp|tftp|scp|awk|xxd|base64)\\\\b\",\n          \"flags\": \"gi\",\n          \"description\": \"Newline followed by a shell command (host\\\\ncat /etc/passwd). Benchmark cmd-newline-injection.\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"cmdi-backtick-command\",\n          \"pattern\": \"`\\\\s*(?:cat|ls|dir|rm|cp|mv|wget|curl|nc|ncat|bash|sh|zsh|ksh|chmod|chown|kill|ps|id|touch|ping|dig|su|head|tail|php|sed|whoami|nslookup|nmap|python3?|perl|ruby|node|eval|exec|sudo|telnet|ssh|ftp|tftp|scp|awk|xxd|base64)\\\\b\",\n          \"flags\": \"gi\",\n          \"description\": \"Backtick command substitution wrapping a known command (`whoami`). Avoids FP on markdown inline code like `npm install`. FPR pass 2026-06-08.\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"cmdi-jndi-lookup\",\n          \"pattern\": \"\\\\$\\\\{jndi:\",\n          \"flags\": \"gi\",\n          \"description\": \"JNDI lookup used by Log4Shell, e.g. ${jndi:ldap://host/a}\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"cmdi-ssi-directive\",\n          \"pattern\": \"<!--\\\\s*#\\\\s*(?:exec|include|echo|config|fsize|flastmod|printenv)\\\\b\",\n          \"flags\": \"gi\",\n          \"description\": \"Server-side include (SSI) directive, e.g. <!--#exec cmd=...-->\",\n          \"redos_safe\": true\n        }\n      ]\n    },\n    \"path_traversal\": {\n      \"name\": \"Path Traversal\",\n      \"severity\": \"high\",\n      \"owasp\": \"A01:2021\",\n      \"rules\": [\n        {\n          \"id\": \"path-dotdot\",\n          \"pattern\": \"\\\\.\\\\./\",\n          \"flags\": \"g\",\n          \"description\": \"Detects ../ sequences\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"path-dotdot-backslash\",\n          \"pattern\": \"\\\\.\\\\.\\\\\\\\\",\n          \"flags\": \"g\",\n          \"description\": \"Detects ..\\\\ sequences\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"path-encoded\",\n          \"pattern\": \"%2e%2e\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects URL-encoded traversal\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"path-double-encoded\",\n          \"pattern\": \"%252e\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects double URL-encoded traversal\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"path-double-encoded-slash\",\n          \"pattern\": \"%252f\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects double URL-encoded forward slash\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"path-dotdotslash-bypass\",\n          \"pattern\": \"\\\\.{2,}[/\\\\\\\\]{2,}\",\n          \"flags\": \"g\",\n          \"description\": \"Detects ....// and ....\\\\\\\\ bypass variants\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"path-null-byte\",\n          \"pattern\": \"%00\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects URL-encoded null byte injection\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"path-null-byte-literal\",\n          \"pattern\": \"\\\\x00\",\n          \"flags\": \"g\",\n          \"description\": \"Detects literal NUL byte in path inputs\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"path-mixed-encoded\",\n          \"pattern\": \"\\\\.\\\\.%2[fF]\",\n          \"flags\": \"g\",\n          \"description\": \"Detects mixed encoding: literal `..` followed by URL-encoded slash (%2F). Benchmark B6 — Python had no coverage; Node had this pattern. 2026-06-07.\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"path-mixed-dot-encoded\",\n          \"pattern\": \"%2e\\\\.[\\\\\\\\/]\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects half-encoded traversal: URL-encoded dot (%2e) followed by a literal dot and a slash (`%2e./`). Node caught this; Python/Go did not. Migration 2026-06-13.\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"path-mixed-dot-encoded-rev\",\n          \"pattern\": \"\\\\.%2e[\\\\\\\\/]\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects half-encoded traversal: literal dot followed by URL-encoded dot (%2e) and a slash (`.%2e/`). Node caught this; Python/Go did not. Migration 2026-06-13.\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"path-overlong-utf8-dot\",\n          \"pattern\": \"%[Cc]0%[Aa][Ee]\",\n          \"flags\": \"g\",\n          \"description\": \"Detects overlong UTF-8 encoding of '.' (%C0%AE). Historic IIS/Apache decoder bypass. Real char `.` is %2E; overlong encoding only appears in evasion attempts. Benchmark B6 gap — neither SDK caught this before. 2026-06-07.\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"path-overlong-utf8-slash\",\n          \"pattern\": \"%[Cc]0%[Aa][Ff]\",\n          \"flags\": \"g\",\n          \"description\": \"Detects overlong UTF-8 encoding of forward slash (%C0%AF). Same IIS/Apache decoder bypass class as path-overlong-utf8-dot. Real slash is %2F; overlong form only appears in evasion. 2026-06-13.\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"path-windows-unc\",\n          \"pattern\": \"\\\\\\\\\\\\\\\\[A-Za-z0-9_.-]+\\\\\\\\\",\n          \"flags\": \"g\",\n          \"description\": \"Detects Windows UNC paths (\\\\\\\\\\\\\\\\server\\\\\\\\share) in user input. Legitimate web-app inputs never contain UNC references; attacker UNC payloads leak SMB auth or pull remote payloads. Benchmark B6. 2026-06-07.\",\n          \"redos_safe\": true\n        }\n      ]\n    },\n    \"prototype_pollution\": {\n      \"name\": \"Prototype Pollution\",\n      \"severity\": \"high\",\n      \"owasp\": \"A03:2021\",\n      \"languages\": [\n        \"javascript\",\n        \"typescript\"\n      ],\n      \"dangerous_keys\": [\n        \"__proto__\",\n        \"constructor\",\n        \"prototype\",\n        \"__definegetter__\",\n        \"__definesetter__\",\n        \"__lookupgetter__\",\n        \"__lookupsetter__\"\n      ]\n    },\n    \"ldap_injection\": {\n      \"name\": \"LDAP Injection\",\n      \"severity\": \"high\",\n      \"owasp\": \"A03:2021\",\n      \"rules\": [\n        {\n          \"id\": \"ldap-special\",\n          \"pattern\": \"[()\\\\\\\\*]\",\n          \"flags\": \"g\",\n          \"description\": \"Detects LDAP special characters. Broad rule for sanitization context only; NOT safe for request-boundary scanning (every parenthesised string trips it). Use 'ldap-injection-strict' below at request boundary.\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"ldap-injection-strict\",\n          \"pattern\": \"\\\\)\\\\s*\\\\(|\\\\*\\\\s*\\\\)\\\\s*\\\\(\",\n          \"flags\": \"g\",\n          \"description\": \"Detects attack-specific LDAP filter-break shapes ')(' and '*)('. Safe to wire into request-boundary scanners. Catches '*)(uid=*))(|(uid=*' style payloads.\",\n          \"redos_safe\": true,\n          \"request_boundary_safe\": true\n        },\n        {\n          \"id\": \"ldap-not-bypass\",\n          \"pattern\": \"\\\\)\\\\s*\\\\(\\\\s*!|&\\\\s*\\\\(\\\\s*!|\\\\|\\\\s*\\\\(\\\\s*!\",\n          \"flags\": \"g\",\n          \"description\": \"Detects LDAP NOT-operator bypass shapes ')(!', '&(!', and '|(!'. Catches injections where attacker appends a NOT clause to enumerate or exclude specific entries, e.g. '*)(uid=*)(!(uid=admin))'. Companion to ldap-injection-strict; together they cover the OR-then-NOT enumeration corpus that legitimate LDAP queries never produce. (improvements.md Q8.)\",\n          \"redos_safe\": true,\n          \"request_boundary_safe\": true\n        },\n        {\n          \"id\": \"ldap-null-byte\",\n          \"pattern\": \"\\\\\\\\00|\\\\x00\",\n          \"flags\": \"g\",\n          \"description\": \"LDAP null-byte truncation (admin\\\\00) used to terminate a filter early and bypass appended constraints. Benchmark ldap-null-byte-truncate.\",\n          \"redos_safe\": true,\n          \"request_boundary_safe\": true\n        }\n      ]\n    },\n    \"xpath_injection\": {\n      \"name\": \"XPath Injection\",\n      \"severity\": \"high\",\n      \"owasp\": \"A03:2021\",\n      \"rules\": [\n        {\n          \"id\": \"xpath-injection-strict\",\n          \"pattern\": \"('\\\\s*(or|and)\\\\s*'|\\\"\\\\s*(or|and)\\\\s*\\\"|\\\\)\\\\s*(or|and)\\\\s*\\\\(|\\\\|\\\\s*/)\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects XPath injection patterns: boolean-injection (' or ' / \\\" or \\\"), function-arity tampering with closing+opening parens around or/and, and union operator before path step. Request-boundary safe.\",\n          \"redos_safe\": true,\n          \"request_boundary_safe\": true\n        },\n        {\n          \"id\": \"xpath-blind-substring\",\n          \"pattern\": \"\\\\bsubstring\\\\s*\\\\(\\\\s*name\\\\s*\\\\(|\\\\bstring-length\\\\s*\\\\(|\\\\bcount\\\\s*\\\\(\\\\s*/\",\n          \"flags\": \"gi\",\n          \"description\": \"Blind XPath extraction via substring(name()), string-length(), count(/...). Benchmark xpath-blind-substring.\",\n          \"redos_safe\": true,\n          \"request_boundary_safe\": true\n        }\n      ]\n    },\n    \"email_header_injection\": {\n      \"name\": \"Email Header Injection (SMTP CRLF)\",\n      \"severity\": \"high\",\n      \"owasp\": \"A03:2021\",\n      \"rules\": [\n        {\n          \"id\": \"email-header-smtp-keyword\",\n          \"pattern\": \"(\\\\r\\\\n|\\\\r|\\\\n)\\\\s*(bcc|cc|to|from|subject|reply-to|return-path|content-type|x-mailer)\\\\s*:\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects SMTP header injection: CR/LF followed by a known SMTP header keyword. Narrow enough for request-boundary scanning because legitimate user input rarely contains '\\\\nBcc:' verbatim.\",\n          \"redos_safe\": true,\n          \"request_boundary_safe\": true\n        },\n        {\n          \"id\": \"email-header-bare-newline\",\n          \"pattern\": \"(\\\\r\\\\n|\\\\r|\\\\n)\\\\s*[a-z][a-z0-9-]{0,40}\\\\s*:\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects bare CR/LF followed by ANY plausible header keyword (not just the SMTP allowlist). Catches MTAs that accept bare LF or bare CR as a header separator (qmail, sendmail variants), where attacker bypasses the strict keyword list by injecting a non-SMTP-keyword header (X-Custom, Authentication-Results, DKIM-Signature, ...). Companion to email-header-smtp-keyword; together they cover the bypass class. (improvements.md Q10.)\",\n          \"redos_safe\": true,\n          \"request_boundary_safe\": true\n        }\n      ]\n    },\n    \"ssti\": {\n      \"name\": \"Server-Side Template Injection (SSTI)\",\n      \"severity\": \"critical\",\n      \"owasp\": \"A03:2021\",\n      \"rules\": [\n        {\n          \"id\": \"ssti-jinja2-twig\",\n          \"pattern\": \"\\\\{\\\\{.*?\\\\}\\\\}\",\n          \"flags\": \"g\",\n          \"description\": \"Detects Jinja2/Twig/Nunjucks template expressions ({{ ... }})\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"ssti-freemarker-spring\",\n          \"pattern\": \"\\\\$\\\\{.*?\\\\}\",\n          \"pattern_safe\": \"\\\\$\\\\{[^}]*[?!()*+\\\\-/][^}]*\\\\}\",\n          \"flags\": \"g\",\n          \"description\": \"Detects Freemarker/Thymeleaf/Spring EL expressions. Detection uses broad pattern; sanitization uses pattern_safe which requires operators/method-calls to avoid false-positives on JS template literals like ${name}.\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"ssti-erb-ejs\",\n          \"pattern\": \"<%[=\\\\-]?.*?%>\",\n          \"flags\": \"gs\",\n          \"description\": \"Detects ERB/EJS template tags (<%= ... %>, <% ... %>)\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"ssti-pug-jade\",\n          \"pattern\": \"#\\\\{.*?\\\\}\",\n          \"pattern_safe\": \"#\\\\{[^}]*[?!()*+\\\\-/][^}]*\\\\}\",\n          \"flags\": \"g\",\n          \"description\": \"Detects Pug/Jade/Slim template expressions. Detection uses broad pattern; sanitization uses pattern_safe to avoid false-positives on Ruby/Pug output like #{name}.\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"ssti-python-class-chain\",\n          \"pattern\": \"__(?:class|mro|subclasses|globals|builtins|import)__\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects Python sandbox escape via dunder attributes\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"ssti-config-leak\",\n          \"pattern\": \"\\\\{\\\\{\\\\s*config[.\\\\[]\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects Jinja2 config/settings leak attempts\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"ssti-jinja2-functions\",\n          \"pattern\": \"\\\\{\\\\{\\\\s*(?:self|request|lipsum|cycler|joiner|namespace|range)\\\\b\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects Jinja2 built-in object/function access\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"ssti-velocity-ognl\",\n          \"pattern\": \"#set\\\\s*\\\\(\\\\s*\\\\$|#foreach\\\\s*\\\\(\\\\s*\\\\$|\\\\$\\\\w+\\\\.(?:exec|getClass|getRuntime|getMethod|invoke)\\\\b\",\n          \"flags\": \"gi\",\n          \"description\": \"Velocity #set/#foreach directives and OGNL/Velocity method calls. Benchmark ssti-velocity-runtime.\",\n          \"redos_safe\": true\n        }\n      ]\n    },\n    \"xml_injection\": {\n      \"name\": \"XML/XXE Injection\",\n      \"severity\": \"critical\",\n      \"owasp\": \"A03:2021\",\n      \"rules\": [\n        {\n          \"id\": \"xxe-doctype\",\n          \"pattern\": \"<!DOCTYPE\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects DOCTYPE declarations\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xxe-entity\",\n          \"pattern\": \"<!ENTITY\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects ENTITY declarations\",\n          \"redos_safe\": true\n        },\n        {\n          \"id\": \"xxe-system\",\n          \"pattern\": \"SYSTEM\\\\s+[\\\"']\",\n          \"flags\": \"gi\",\n          \"description\": \"Detects SYSTEM references\",\n          \"redos_safe\": true\n        }\n      ]\n    }\n  },\n  \"security_headers\": {\n    \"Content-Security-Policy\": \"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; object-src 'none'; frame-ancestors 'none';\",\n    \"X-Content-Type-Options\": \"nosniff\",\n    \"X-Frame-Options\": \"DENY\",\n    \"X-XSS-Protection\": \"0\",\n    \"Strict-Transport-Security\": \"max-age=31536000; includeSubDomains\",\n    \"Referrer-Policy\": \"strict-origin-when-cross-origin\",\n    \"Permissions-Policy\": \"geolocation=(), microphone=(), camera=()\",\n    \"X-Permitted-Cross-Domain-Policies\": \"none\",\n    \"Cache-Control\": \"no-store, no-cache, must-revalidate, proxy-revalidate\",\n    \"Pragma\": \"no-cache\",\n    \"Expires\": \"0\"\n  },\n  \"rate_limiting\": {\n    \"default_max\": 100,\n    \"default_window_ms\": 60000,\n    \"headers\": {\n      \"limit\": \"X-RateLimit-Limit\",\n      \"remaining\": \"X-RateLimit-Remaining\",\n      \"reset\": \"X-RateLimit-Reset\"\n    }\n  },\n  \"sensitive_keys\": [\n    \"password\",\n    \"passwd\",\n    \"pwd\",\n    \"secret\",\n    \"token\",\n    \"apikey\",\n    \"api_key\",\n    \"apiKey\",\n    \"auth\",\n    \"authorization\",\n    \"credit_card\",\n    \"creditcard\",\n    \"cc\",\n    \"ssn\",\n    \"social_security\",\n    \"private_key\",\n    \"privateKey\",\n    \"access_token\",\n    \"accessToken\",\n    \"refresh_token\",\n    \"refreshToken\",\n    \"bearer\",\n    \"jwt\",\n    \"session\",\n    \"cookie\",\n    \"x-api-key\",\n    \"x-auth-token\",\n    \"credentials\"\n  ],\n  \"validation\": {\n    \"email\": \"^[^\\\\s@]+@[^\\\\s@]+\\\\.[^\\\\s@]+$\",\n    \"url\": \"^https?://[^\\\\s/$.?#].[^\\\\s]*$\",\n    \"uuid\": \"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$\",\n    \"ipv4\": \"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$\"\n  }\n}\n","/**\n * @module @arcis/node/core/patterns-loader\n *\n * Loads the shared security regex patterns from the bundled\n * `data/patterns.json` (a copy of the canonical `packages/core/patterns.json`,\n * kept byte-identical by the CI data-sync-check). This is the Node counterpart\n * of Go's `sanitizers/loader.go` and Python's `core/constants.load_patterns` +\n * `_compile_rules`.\n *\n * Why this exists: pre-migration, Node hardcoded every regex in `constants.ts`,\n * so each pattern edit was a manual dual-write against patterns.json (which\n * Python + Go already load at runtime). That is a Pattern 2 violation\n * (Shared Pattern Repository). Sourcing the arrays from patterns.json here\n * makes patterns.json the single source for all three SDKs.\n *\n * The JSON is a static `import`, so tsup inlines it into the CJS + ESM bundles\n * at build time (same as `bot-detection.ts` does with `bot-patterns.json`); no\n * runtime filesystem access. resolveJsonModule is already enabled in tsconfig.\n */\n\nimport patternsData from '../data/patterns.json';\n\ninterface PatternRule {\n  id: string;\n  pattern: string;\n  pattern_safe?: string;\n  flags?: string;\n}\n\ninterface PatternCategory {\n  rules?: PatternRule[];\n  dangerous_keys?: string[];\n}\n\ninterface PatternsSpec {\n  version: string;\n  patterns: Record<string, PatternCategory>;\n}\n\nconst spec = patternsData as unknown as PatternsSpec;\n\n/** Valid JavaScript RegExp flags. patterns.json uses g/i/m; anything else is dropped. */\nconst VALID_JS_FLAGS = new Set(['g', 'i', 'm', 's', 'u', 'y']);\n\nfunction normalizeFlags(flags: string | undefined): string {\n  if (!flags) return '';\n  let out = '';\n  for (const ch of flags) {\n    if (VALID_JS_FLAGS.has(ch) && !out.includes(ch)) out += ch;\n  }\n  return out;\n}\n\n/**\n * Compile every rule in a patterns.json category into a RegExp array, in file\n * order. Prefers the ReDoS-safe `pattern_safe` variant when present (parity\n * with Go's compileCategory / Python's _compile_rules). A category with no\n * rules returns an empty array.\n */\nexport function compileCategory(category: string): RegExp[] {\n  const cat = spec.patterns[category];\n  if (!cat?.rules) return [];\n  const out: RegExp[] = [];\n  for (const rule of cat.rules) {\n    const raw = rule.pattern_safe || rule.pattern;\n    if (!raw) continue;\n    out.push(new RegExp(raw, normalizeFlags(rule.flags)));\n  }\n  return out;\n}\n\n/**\n * Compile a single named rule from a category into one RegExp, or undefined if\n * the rule id is absent. Used where Node consumes a single pattern rather than\n * a list (e.g. the string-form NoSQL operator check).\n */\nexport function compileRule(category: string, id: string, flags?: string): RegExp | undefined {\n  const rule = spec.patterns[category]?.rules?.find((r) => r.id === id);\n  if (!rule) return undefined;\n  const raw = rule.pattern_safe || rule.pattern;\n  if (!raw) return undefined;\n  return new RegExp(raw, normalizeFlags(flags ?? rule.flags));\n}\n\n/**\n * Return the `dangerous_keys` list for a category (e.g. `nosql_injection`,\n * `prototype_pollution`), or an empty array if the category has none.\n */\nexport function dangerousKeysFor(category: string): string[] {\n  return spec.patterns[category]?.dangerous_keys ?? [];\n}\n\n/** The version string from the bundled patterns.json. Used by tests/diagnostics. */\nexport const PATTERNS_VERSION = spec.version;\n","/**\n * @module @arcis/node/core/constants\n * Named constants for Arcis - no magic numbers\n */\n\nimport { compileCategory, compileRule, dangerousKeysFor } from './patterns-loader';\n\n// =============================================================================\n// INPUT LIMITS\n// =============================================================================\nexport const INPUT = {\n  /** Default maximum input size (1MB) */\n  DEFAULT_MAX_SIZE: 1_000_000,\n  /** Maximum recursion depth for nested objects */\n  MAX_RECURSION_DEPTH: 10,\n} as const;\n\n// =============================================================================\n// RATE LIMITING\n// =============================================================================\nexport const RATE_LIMIT = {\n  /** Default window size (1 minute) */\n  DEFAULT_WINDOW_MS: 60_000,\n  /** Default max requests per window */\n  DEFAULT_MAX_REQUESTS: 100,\n  /** Default HTTP status code for rate limited responses */\n  DEFAULT_STATUS_CODE: 429,\n  /** Default error message */\n  DEFAULT_MESSAGE: 'Too many requests, please try again later.',\n  /** Minimum window size (1 second) */\n  MIN_WINDOW_MS: 1_000,\n  /** Maximum window size (24 hours) */\n  MAX_WINDOW_MS: 86_400_000,\n} as const;\n\n// =============================================================================\n// SECURITY HEADERS\n// =============================================================================\nexport const HEADERS = {\n  /** Default Content Security Policy */\n  DEFAULT_CSP: [\n    \"default-src 'self'\",\n    \"script-src 'self'\",\n    \"style-src 'self' 'unsafe-inline'\",\n    \"img-src 'self' data: https:\",\n    \"font-src 'self'\",\n    \"object-src 'none'\",\n    \"frame-ancestors 'none'\",\n  ].join('; '),\n  /** Default HSTS max age (1 year in seconds) */\n  HSTS_MAX_AGE: 31_536_000,\n  /** Default X-Frame-Options value */\n  FRAME_OPTIONS: 'DENY' as const,\n  /** Default X-Content-Type-Options value */\n  CONTENT_TYPE_OPTIONS: 'nosniff',\n  /** Default Referrer-Policy value */\n  REFERRER_POLICY: 'strict-origin-when-cross-origin',\n  /** Default Permissions-Policy value */\n  PERMISSIONS_POLICY: 'geolocation=(), microphone=(), camera=()',\n  /** Default Cache-Control value for security */\n  CACHE_CONTROL: 'no-store, no-cache, must-revalidate, proxy-revalidate',\n} as const;\n\n// =============================================================================\n// XSS PATTERNS (sourced from patterns.json)\n// =============================================================================\n\n/**\n * XSS patterns, compiled from the shared `patterns.json` `xss` category.\n *\n * Both detection (detectXss) and removal (sanitizeXss) iterate the same rule\n * list: the rules are precise capture patterns (full tag / attribute / protocol)\n * so they double as removal targets, and patterns.json file order keeps every\n * block rule (e.g. `<script>...</script>`) ahead of its bare-tag counterpart so\n * removal strips the larger match first. Pre-migration these were two hardcoded\n * arrays (a broad detect set + a precise remove set); single-sourcing them here\n * ends the dual-write against patterns.json and converges Node onto the same\n * detection Python + Go already ship (Pattern 2 + Pattern 7).\n */\nexport const XSS_PATTERNS = compileCategory('xss');\n\n/** Removal patterns for sanitizeXss(): the same patterns.json `xss` rules.\n *  A separate compiled array so its RegExp lastIndex state is independent of\n *  the detection pass. */\nexport const XSS_REMOVE_PATTERNS = compileCategory('xss');\n\n// =============================================================================\n// SQL INJECTION PATTERNS (sourced from patterns.json)\n// =============================================================================\n/** Compiled from the shared `patterns.json` `sql_injection` category. The\n *  quoted-boolean rules use RE2-safe `['\"]...['\"]` (no backreference) since\n *  patterns.json is also consumed by Go's RE2 engine; validated equivalent to\n *  the former backreference forms on the O'Brien / tautology corpus. */\nexport const SQL_PATTERNS = compileCategory('sql_injection');\n\n// =============================================================================\n// PATH TRAVERSAL PATTERNS (sourced from patterns.json)\n// =============================================================================\n/** Compiled from the shared `patterns.json` `path_traversal` category. */\nexport const PATH_PATTERNS = compileCategory('path_traversal');\n\n// =============================================================================\n// COMMAND INJECTION PATTERNS (sourced from patterns.json)\n// =============================================================================\n/** Compiled from the shared `patterns.json` `command_injection` category. */\nexport const COMMAND_PATTERNS = compileCategory('command_injection');\n\n// =============================================================================\n// DANGEROUS KEYS\n// =============================================================================\n\n/**\n * Prototype pollution keys to block.\n * Stored lowercase — always compare with key.toLowerCase().\n *\n * Includes:\n * - __proto__: direct prototype assignment\n * - constructor: access to constructor.prototype chain\n * - prototype: direct prototype property\n * - __defineGetter__/__defineSetter__: legacy property definition (can override getters/setters)\n * - __lookupGetter__/__lookupSetter__: legacy property introspection\n */\nexport const DANGEROUS_PROTO_KEYS = new Set(dangerousKeysFor('prototype_pollution'));\n\n/** MongoDB operators to block, from `patterns.json` nosql_injection.dangerous_keys. */\nexport const NOSQL_DANGEROUS_KEYS = new Set(dangerousKeysFor('nosql_injection'));\n\n/**\n * String-form NoSQL operator detection (block-mode scanThreats).\n *\n * NOSQL_DANGEROUS_KEYS catches operators that arrive as OBJECT KEYS\n * (`{\"$gt\": \"\"}`). But MongoDB operators also bypass as STRING VALUES —\n * query params like `?username[$ne]=1` arrive as the literal string\n * `$ne` before the body parser ever builds an object, and mongo-shell\n * payloads (`$where: '1==1'`) are plain strings. Node previously had no\n * string-level NoSQL check, so GoTestWAF scored NoSQL at 0% while Python\n * (which loads the shared `nosql-operators` rule) caught these. This\n * closes that Pattern-7 parity gap.\n *\n * Sourced from the `nosql-operators` rule in patterns.json. The trailing\n * `\\b` word boundary keeps `$invoice`/`$order`/`$index` from matching\n * `$in`/`$or` (a false-positive class the un-bounded rule had).\n */\nconst nosqlStringRule = compileRule('nosql_injection', 'nosql-operators');\nif (!nosqlStringRule) {\n  throw new Error('arcis: nosql-operators rule missing from patterns.json');\n}\nexport const NOSQL_STRING_PATTERN = nosqlStringRule;\n\n/**\n * Identity/auth field names that must hold a scalar value. A field here\n * carrying an array or object is a NoSQL type-juggling operator-injection\n * shape (e.g. {\"username\":[\"admin\"]}). v1.7 nosql-type-juggle.\n */\nexport const AUTH_FIELDS = new Set([\n  'username', 'user', 'userid', 'user_id', 'login', 'email',\n  'password', 'pass', 'passwd', 'pwd', 'token', 'apikey', 'api_key',\n  'secret', 'otp', 'pin',\n]);\n\n// =============================================================================\n// REDACTION\n// =============================================================================\nexport const REDACTION = {\n  /** Replacement text for redacted values */\n  REPLACEMENT: '[REDACTED]',\n  /** Truncation indicator */\n  TRUNCATED: '[TRUNCATED]',\n  /** Max depth indicator */\n  MAX_DEPTH: '[MAX_DEPTH]',\n  /** Default max message length */\n  DEFAULT_MAX_LENGTH: 10_000,\n  /** Default sensitive keys to redact */\n  SENSITIVE_KEYS: new Set([\n    'password', 'passwd', 'pwd', 'secret', 'token', 'apikey',\n    'api_key', 'apiKey', 'auth', 'authorization', 'credit_card',\n    'creditcard', 'cc', 'ssn', 'social_security', 'private_key',\n    'privateKey', 'access_token', 'accessToken', 'refresh_token',\n    'refreshToken', 'bearer', 'jwt', 'session', 'cookie',\n    'credentials', 'x-api-key', 'x-auth-token',\n  ]),\n} as const;\n\n// =============================================================================\n// VALIDATION PATTERNS\n// =============================================================================\nexport const VALIDATION = {\n  /**\n   * Email regex pattern.\n   * Rejects consecutive dots in local part (e.g. test..foo@example.com),\n   * leading/trailing dots, and other common invalid forms.\n   */\n  EMAIL: /^[^\\s@.][^\\s@]*(?:\\.[^\\s@.][^\\s@]*)*@[^\\s@]+\\.[^\\s@]+$/,\n  /**\n   * URL regex pattern.\n   * Only allows http:// and https:// (case-insensitive scheme per\n   * RFC 3986); explicitly rejects javascript:, data:, vbscript:, and\n   * other dangerous URI schemes.\n   */\n  URL: /^https?:\\/\\/[^\\s/$.?#][^\\s]*$/i,\n  /** UUID regex pattern (v4) */\n  UUID: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,\n} as const;\n\n// =============================================================================\n// ERROR MESSAGES\n// =============================================================================\nexport const ERRORS = {\n  /** Generic error message (production) */\n  INTERNAL_SERVER_ERROR: 'Internal Server Error',\n  /** Input too large error */\n  INPUT_TOO_LARGE: (maxSize: number) => `Input exceeds maximum size of ${maxSize} bytes`,\n  /** Validation error messages */\n  VALIDATION: {\n    REQUIRED: (field: string) => `${field} is required`,\n    INVALID_TYPE: (field: string, type: string) => `${field} must be a ${type}`,\n    MIN_LENGTH: (field: string, min: number) => `${field} must be at least ${min} characters`,\n    MAX_LENGTH: (field: string, max: number) => `${field} must be at most ${max} characters`,\n    MIN_VALUE: (field: string, min: number) => `${field} must be at least ${min}`,\n    MAX_VALUE: (field: string, max: number) => `${field} must be at most ${max}`,\n    INVALID_FORMAT: (field: string) => `${field} format is invalid`,\n    INVALID_EMAIL: (field: string) => `${field} must be a valid email`,\n    INVALID_URL: (field: string) => `${field} must be a valid URL`,\n    INVALID_UUID: (field: string) => `${field} must be a valid UUID`,\n    INVALID_ENUM: (field: string, values: unknown[]) => `${field} must be one of: ${values.join(', ')}`,\n    MIN_ITEMS: (field: string, min: number) => `${field} must have at least ${min} items`,\n    MAX_ITEMS: (field: string, max: number) => `${field} must have at most ${max} items`,\n  },\n} as const;\n\n// =============================================================================\n// BLOCKED TEXT (for sanitizer replacements)\n// =============================================================================\nexport const BLOCKED = '[BLOCKED]' as const;\n","/**\n * @module @arcis/node/logging/redactor\n * Safe logging with PII/secret redaction\n */\n\nimport { REDACTION, INPUT } from '../core/constants';\nimport type { LogOptions, SafeLogger } from '../core/types';\n\nconst LOG_LEVELS: Record<string, number> = {\n  debug: 0,\n  info: 1,\n  warn: 2,\n  error: 3,\n  silent: 4,\n};\n\n/**\n * Create a safe logger that redacts sensitive data and prevents log injection.\n * \n * @param options - Logger configuration\n * @returns SafeLogger instance\n * \n * @example\n * const logger = createSafeLogger();\n * logger.info('User login', { email: 'user@test.com', password: 'secret' });\n * // Logs: { \"email\": \"user@test.com\", \"password\": \"[REDACTED]\" }\n * \n * @example\n * // With custom redact keys\n * const logger = createSafeLogger({ redactKeys: ['customToken', 'internalId'] });\n */\nexport function createSafeLogger(options: LogOptions = {}): SafeLogger {\n  const {\n    redactKeys = [],\n    maxLength = REDACTION.DEFAULT_MAX_LENGTH,\n    redactPatterns = [],\n    level: minLevel = 'debug',\n  } = options;\n\n  const minLevelNum = LOG_LEVELS[minLevel] ?? 0;\n\n  // Combine default and custom keys (lowercase for case-insensitive matching)\n  const allRedactKeys = new Set([\n    ...Array.from(REDACTION.SENSITIVE_KEYS),\n    ...redactKeys.map(k => k.toLowerCase()),\n  ]);\n\n  /**\n   * Redact sensitive data from an object recursively.\n   */\n  function redact(obj: unknown, depth = 0): unknown {\n    if (depth > INPUT.MAX_RECURSION_DEPTH) return REDACTION.MAX_DEPTH;\n    if (obj === null || obj === undefined) return obj;\n\n    if (typeof obj === 'string') {\n      return redactString(obj, maxLength, redactPatterns);\n    }\n\n    if (typeof obj !== 'object') return obj;\n\n    if (Array.isArray(obj)) {\n      return obj.map(item => redact(item, depth + 1));\n    }\n\n    const result: Record<string, unknown> = {};\n    for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n      if (allRedactKeys.has(key.toLowerCase())) {\n        result[key] = REDACTION.REPLACEMENT;\n      } else {\n        result[key] = redact(value, depth + 1);\n      }\n    }\n    return result;\n  }\n\n  /**\n   * Log a message at the specified level.\n   */\n  function log(level: string, message: string, data?: unknown): void {\n    // Early exit: skip all work if message level is below minimum\n    const levelNum = LOG_LEVELS[level] ?? 0;\n    if (levelNum < minLevelNum) return;\n\n    const entry: Record<string, unknown> = {\n      timestamp: new Date().toISOString(),\n      level,\n      message: redactString(message, maxLength, redactPatterns),\n    };\n\n    if (data !== undefined) {\n      entry.data = redact(data);\n    }\n\n    // eslint-disable-next-line no-console\n    console.log(JSON.stringify(entry));\n  }\n\n  return {\n    log,\n    info: (msg: string, data?: unknown) => log('info', msg, data),\n    warn: (msg: string, data?: unknown) => log('warn', msg, data),\n    error: (msg: string, data?: unknown) => log('error', msg, data),\n    debug: (msg: string, data?: unknown) => log('debug', msg, data),\n  };\n}\n\n/**\n * Redact a string value.\n * Removes newlines (log injection prevention), applies patterns, and truncates.\n */\nfunction redactString(str: string, maxLength: number, patterns: RegExp[]): string {\n  // Remove newlines/tabs (log injection prevention) and genuine control characters.\n  // Only strip C0/C1 control chars and null bytes — preserve all printable Unicode\n  // (CJK, Cyrillic, Arabic, etc.) so multilingual content isn't silently lost.\n  let safe = str\n    .replace(/[\\r\\n\\t]/g, ' ')\n    .replace(/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F\\x80-\\x9F]/g, '');\n\n  // Apply custom redaction patterns\n  for (const pattern of patterns) {\n    safe = safe.replace(pattern, REDACTION.REPLACEMENT);\n  }\n\n  // Truncate if too long\n  if (safe.length > maxLength) {\n    safe = safe.substring(0, maxLength) + `...${REDACTION.TRUNCATED}`;\n  }\n\n  return safe;\n}\n\n/**\n * Create a redactor function for custom use.\n * \n * @param sensitiveKeys - Keys to redact\n * @returns Redactor function\n */\nexport function createRedactor(sensitiveKeys: string[] = []): (obj: unknown) => unknown {\n  const allKeys = new Set([\n    ...Array.from(REDACTION.SENSITIVE_KEYS),\n    ...sensitiveKeys.map(k => k.toLowerCase()),\n  ]);\n\n  function redact(obj: unknown, depth = 0): unknown {\n    if (depth > INPUT.MAX_RECURSION_DEPTH) return REDACTION.MAX_DEPTH;\n    if (obj === null || obj === undefined) return obj;\n    if (typeof obj !== 'object') return obj;\n\n    if (Array.isArray(obj)) {\n      return obj.map(item => redact(item, depth + 1));\n    }\n\n    const result: Record<string, unknown> = {};\n    for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n      if (allKeys.has(key.toLowerCase())) {\n        result[key] = REDACTION.REPLACEMENT;\n      } else {\n        result[key] = redact(value, depth + 1);\n      }\n    }\n    return result;\n  }\n\n  return redact;\n}\n\n/**\n * Alias for createSafeLogger\n * @see createSafeLogger\n */\nexport const safeLog = createSafeLogger;\n"]}