{"version":3,"sources":["../../src/data/patterns.json","../../src/core/patterns-loader.ts","../../src/core/constants.ts","../../src/core/errors.ts","../../src/sanitizers/utils.ts","../../src/sanitizers/xss.ts","../../src/sanitizers/sql.ts","../../src/sanitizers/path.ts","../../src/sanitizers/command.ts","../../src/sanitizers/ssti.ts","../../src/sanitizers/xxe.ts","../../src/sanitizers/ldap.ts","../../src/sanitizers/xpath.ts","../../src/sanitizers/headers.ts","../../src/sanitizers/deserialization.ts","../../src/sanitizers/nosql.ts","../../src/sanitizers/sanitize.ts","../../src/sanitizers/prototype.ts","../../src/sanitizers/jsonp.ts","../../src/sanitizers/pii.ts","../../src/sanitizers/encode.ts","../../src/sanitizers/graphql.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/core/errors\n * Custom error classes for Arcis\n */\n\n/**\n * Base class for all Arcis errors\n */\nexport class ArcisError extends Error {\n  public readonly statusCode: number;\n  public readonly code: string;\n  /** Whether the error message is safe to expose to API clients. */\n  public readonly expose: boolean;\n\n  constructor(message: string, statusCode = 500, code = 'ARCIS_ERROR') {\n    super(message);\n    this.name = 'ArcisError';\n    this.statusCode = statusCode;\n    this.code = code;\n    // Client errors (4xx) have controlled messages — safe to expose.\n    // Server errors (5xx) may contain internal details — hide by default.\n    this.expose = statusCode < 500;\n\n    // Maintains proper stack trace for where error was thrown (V8 engines)\n    if (Error.captureStackTrace) {\n      Error.captureStackTrace(this, this.constructor);\n    }\n  }\n}\n\n/**\n * Error thrown when input validation fails\n */\nexport class ValidationError extends ArcisError {\n  public readonly errors: string[];\n\n  constructor(errors: string[]) {\n    super('Validation failed', 400, 'VALIDATION_ERROR');\n    this.name = 'ValidationError';\n    this.errors = errors;\n  }\n}\n\n/** Alias for ValidationError (backwards compatibility) */\nexport { ValidationError as ArcisValidationError };\n\n/**\n * Error thrown when rate limit is exceeded\n */\nexport class RateLimitError extends ArcisError {\n  public readonly retryAfter: number;\n\n  constructor(message: string, retryAfter: number) {\n    super(message, 429, 'RATE_LIMIT_EXCEEDED');\n    this.name = 'RateLimitError';\n    this.retryAfter = retryAfter;\n  }\n}\n\n/**\n * Error thrown when input is too large\n */\nexport class InputTooLargeError extends ArcisError {\n  public readonly maxSize: number;\n  public readonly actualSize: number;\n\n  constructor(maxSize: number, actualSize: number) {\n    super(`Input exceeds maximum size of ${maxSize} bytes`, 413, 'INPUT_TOO_LARGE');\n    this.name = 'InputTooLargeError';\n    this.maxSize = maxSize;\n    this.actualSize = actualSize;\n  }\n}\n\n/**\n * Error thrown when security threat is detected\n */\nexport class SecurityThreatError extends ArcisError {\n  public readonly threatType: string;\n  public readonly pattern: string;\n\n  constructor(threatType: string, pattern: string) {\n    super('Request blocked for security reasons', 400, 'SECURITY_THREAT');\n    this.name = 'SecurityThreatError';\n    this.threatType = threatType;\n    this.pattern = pattern;\n  }\n}\n\n/**\n * Error thrown when sanitization fails\n */\nexport class SanitizationError extends ArcisError {\n  constructor(message: string) {\n    super(message, 400, 'SANITIZATION_ERROR');\n    this.name = 'SanitizationError';\n  }\n}\n","/**\n * @module @arcis/node/sanitizers/utils\n * Shared utilities for sanitizers\n */\n\n/**\n * Encodes HTML entities to prevent interpretation as markup.\n * \n * @param str - The string to encode\n * @returns The encoded string\n */\nexport function encodeHtmlEntities(str: string): string {\n  return str\n    .replace(/&/g, '&amp;')\n    .replace(/</g, '&lt;')\n    .replace(/>/g, '&gt;')\n    .replace(/\"/g, '&quot;')\n    .replace(/'/g, '&#x27;');\n}\n\n/**\n * Checks if a value is a plain object (not null, array, Date, etc.)\n * \n * @param value - Value to check\n * @returns True if plain object\n */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n  if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n    return false;\n  }\n  // Check the actual prototype chain rather than toString, which can be spoofed\n  // via Symbol.toStringTag. Accepts both Object.prototype (plain {}) and null\n  // prototype objects (Object.create(null)).\n  const proto = Object.getPrototypeOf(value as object);\n  return proto === Object.prototype || proto === null;\n}\n","/**\n * @module @arcis/node/sanitizers/xss\n * XSS (Cross-Site Scripting) prevention\n */\n\nimport { XSS_PATTERNS, XSS_REMOVE_PATTERNS } from '../core/constants';\nimport { encodeHtmlEntities } from './utils';\nimport type { SanitizeResult, ThreatInfo } from '../core/types';\n\n/**\n * Sanitizes a string to prevent XSS attacks.\n * \n * Strategy:\n * 1. Remove dangerous patterns (script tags, event handlers, etc.)\n * 2. HTML-encode the remaining content\n * \n * @param input - The string to sanitize\n * @param collectThreats - Whether to collect threat information (default: false for performance)\n * @returns Sanitized string or SanitizeResult if collectThreats is true\n * \n * @example\n * sanitizeXss(\"<script>alert('xss')</script>\")\n * // Returns: \"&lt;script&gt;alert(&#x27;xss&#x27;)&lt;/script&gt;\"\n * \n * @example\n * sanitizeXss(\"<img onerror='alert(1)'>\")\n * // Returns: \"&lt;img&gt;\" (event handler removed)\n */\nexport function sanitizeXss(input: string, collectThreats?: false, htmlEncode?: boolean): string;\nexport function sanitizeXss(input: string, collectThreats: true, htmlEncode?: boolean): SanitizeResult;\nexport function sanitizeXss(input: string, collectThreats = false, htmlEncode = false): string | SanitizeResult {\n  if (typeof input !== 'string') {\n    return collectThreats \n      ? { value: String(input), wasSanitized: false, threats: [] }\n      : String(input);\n  }\n\n  const threats: ThreatInfo[] = [];\n  let value = input;\n  let wasSanitized = false;\n\n  // Remove dangerous patterns FIRST — XSS_REMOVE_PATTERNS is the single\n  // source of truth (defined in constants.ts alongside XSS_PATTERNS).\n  for (const pattern of XSS_REMOVE_PATTERNS) {\n    pattern.lastIndex = 0;\n    if (pattern.test(value)) {\n      pattern.lastIndex = 0;\n      \n      if (collectThreats) {\n        const matches = value.match(pattern);\n        if (matches) {\n          for (const match of matches) {\n            threats.push({\n              type: 'xss',\n              pattern: pattern.source,\n              original: match,\n            });\n          }\n        }\n      }\n      \n      value = value.replace(pattern, '');\n      wasSanitized = true;\n    }\n  }\n\n  // HTML-encode only when explicitly requested (SSR/template context).\n  // Do NOT encode by default — this is a REST API middleware; encoding\n  // here corrupts JSON data with HTML entities (&lt;, &amp;, etc.) that\n  // consumers would receive verbatim.\n  if (htmlEncode) {\n    const encoded = encodeHtmlEntities(value);\n    if (encoded !== value) {\n      wasSanitized = true;\n    }\n    value = encoded;\n  }\n\n  if (collectThreats) {\n    return { value, wasSanitized, threats };\n  }\n  \n  return value;\n}\n\n/**\n * Checks if a string contains potential XSS patterns.\n * Does not sanitize — use sanitizeXss() for that.\n * \n * @param input - The string to check\n * @returns True if XSS patterns detected\n */\nexport function detectXss(input: string): boolean {\n  if (typeof input !== 'string') return false;\n\n  // All XSS detection now flows through the shared patterns.json `xss` rules\n  // (event handlers, javascript:/vbscript:/data: protocols, tags). The former\n  // inline fast-path checks were a strict subset of these rules, so they were\n  // removed when the patterns moved to patterns.json (single source).\n  for (const pattern of XSS_PATTERNS) {\n    pattern.lastIndex = 0;\n    if (pattern.test(input)) {\n      return true;\n    }\n  }\n\n  return false;\n}\n","/**\n * @module @arcis/node/sanitizers/sql\n * SQL injection prevention\n */\n\nimport { SQL_PATTERNS } from '../core/constants';\nimport type { SanitizeResult, ThreatInfo } from '../core/types';\n\n/**\n * Sanitizes a string to prevent SQL injection attacks.\n * Replaces dangerous SQL patterns with [BLOCKED].\n * \n * @param input - The string to sanitize\n * @param collectThreats - Whether to collect threat information (default: false for performance)\n * @returns Sanitized string or SanitizeResult if collectThreats is true\n * \n * @example\n * sanitizeSql(\"'; DROP TABLE users; --\")\n * // Returns: \"';  TABLE users  \"\n */\nexport function sanitizeSql(input: string, collectThreats?: false): string;\nexport function sanitizeSql(input: string, collectThreats: true): SanitizeResult;\nexport function sanitizeSql(input: string, collectThreats = false): string | SanitizeResult {\n  if (typeof input !== 'string') {\n    return collectThreats \n      ? { value: String(input), wasSanitized: false, threats: [] }\n      : String(input);\n  }\n\n  const threats: ThreatInfo[] = [];\n  let value = input;\n  let wasSanitized = false;\n\n  for (const pattern of SQL_PATTERNS) {\n    // Reset regex lastIndex for global patterns\n    pattern.lastIndex = 0;\n    \n    if (pattern.test(value)) {\n      pattern.lastIndex = 0; // Reset again for replace\n      \n      if (collectThreats) {\n        const matches = value.match(pattern);\n        if (matches) {\n          for (const match of matches) {\n            threats.push({\n              type: 'sql_injection',\n              pattern: pattern.source,\n              original: match,\n            });\n          }\n        }\n      }\n      \n      // Replace the matched content with a space to avoid concatenating surrounding\n      // tokens into new dangerous strings (e.g. \"SELECTname\" after stripping \"SELECT\").\n      value = value.replace(pattern, ' ');\n      wasSanitized = true;\n    }\n  }\n\n  if (collectThreats) {\n    return { value, wasSanitized, threats };\n  }\n  \n  return value;\n}\n\n/**\n * Checks if a string contains potential SQL injection patterns.\n * Does not sanitize — use sanitizeSql() for that.\n * \n * @param input - The string to check\n * @returns True if SQL injection patterns detected\n */\nexport function detectSql(input: string): boolean {\n  if (typeof input !== 'string') return false;\n  \n  for (const pattern of SQL_PATTERNS) {\n    pattern.lastIndex = 0;\n    if (pattern.test(input)) {\n      return true;\n    }\n  }\n  \n  return false;\n}\n","/**\n * @module @arcis/node/sanitizers/path\n * Path traversal prevention\n */\n\nimport { PATH_PATTERNS } from '../core/constants';\nimport type { SanitizeResult, ThreatInfo } from '../core/types';\n\n/**\n * Sanitizes a string to prevent path traversal attacks.\n * Removes ../ and ..\\ patterns (including URL-encoded variants).\n * \n * @param input - The string to sanitize\n * @param collectThreats - Whether to collect threat information (default: false for performance)\n * @returns Sanitized string or SanitizeResult if collectThreats is true\n * \n * @example\n * sanitizePath(\"../../etc/passwd\")\n * // Returns: \"etc/passwd\"\n */\nexport function sanitizePath(input: string, collectThreats?: false): string;\nexport function sanitizePath(input: string, collectThreats: true): SanitizeResult;\nexport function sanitizePath(input: string, collectThreats = false): string | SanitizeResult {\n  if (typeof input !== 'string') {\n    return collectThreats \n      ? { value: String(input), wasSanitized: false, threats: [] }\n      : String(input);\n  }\n\n  const threats: ThreatInfo[] = [];\n  let value = input;\n  let wasSanitized = false;\n\n  // SECURITY: Normalize Unicode to NFKC before pattern matching.\n  // Fullwidth dot U+FF0E normalizes to '.', preventing ．．/ bypass of ../ detection.\n  value = value.normalize('NFKC');\n\n  // Apply patterns repeatedly until the string stops changing.\n  // Single-pass stripping is bypassable: \"....//\".replace(\"../\",\"\") → \"../\"\n  let prev: string;\n  do {\n    prev = value;\n    for (const pattern of PATH_PATTERNS) {\n      pattern.lastIndex = 0;\n\n      if (pattern.test(value)) {\n        pattern.lastIndex = 0;\n\n        if (collectThreats) {\n          const matches = value.match(pattern);\n          if (matches) {\n            for (const match of matches) {\n              threats.push({\n                type: 'path_traversal',\n                pattern: pattern.source,\n                original: match,\n              });\n            }\n          }\n        }\n\n        value = value.replace(pattern, '');\n        wasSanitized = true;\n      }\n    }\n  } while (value !== prev);\n\n  if (collectThreats) {\n    return { value, wasSanitized, threats };\n  }\n  \n  return value;\n}\n\n/**\n * Checks if a string contains path traversal patterns.\n * Does not sanitize — use sanitizePath() for that.\n * \n * @param input - The string to check\n * @returns True if path traversal patterns detected\n */\nexport function detectPathTraversal(input: string): boolean {\n  if (typeof input !== 'string') return false;\n\n  // SECURITY: Normalize Unicode to NFKC — same as sanitizePath\n  const normalized = input.normalize('NFKC');\n\n  for (const pattern of PATH_PATTERNS) {\n    pattern.lastIndex = 0;\n    if (pattern.test(normalized)) {\n      return true;\n    }\n  }\n  \n  return false;\n}\n","/**\n * @module @arcis/node/sanitizers/command\n * Command injection prevention\n */\n\nimport { COMMAND_PATTERNS } from '../core/constants';\nimport type { SanitizeResult, ThreatInfo } from '../core/types';\n\n/**\n * Sanitizes a string to prevent command injection attacks.\n * Replaces shell metacharacters and dangerous commands with [BLOCKED].\n * \n * @param input - The string to sanitize\n * @param collectThreats - Whether to collect threat information (default: false for performance)\n * @returns Sanitized string or SanitizeResult if collectThreats is true\n * \n * @example\n * sanitizeCommand(\"file.txt; rm -rf /\")\n * // Returns: \"file.txt  rm -rf /\"\n */\nexport function sanitizeCommand(input: string, collectThreats?: false): string;\nexport function sanitizeCommand(input: string, collectThreats: true): SanitizeResult;\nexport function sanitizeCommand(input: string, collectThreats = false): string | SanitizeResult {\n  if (typeof input !== 'string') {\n    return collectThreats \n      ? { value: String(input), wasSanitized: false, threats: [] }\n      : String(input);\n  }\n\n  const threats: ThreatInfo[] = [];\n  let value = input;\n  let wasSanitized = false;\n\n  for (const pattern of COMMAND_PATTERNS) {\n    // Reset regex lastIndex for global patterns\n    pattern.lastIndex = 0;\n    \n    if (pattern.test(value)) {\n      pattern.lastIndex = 0; // Reset again for replace\n      \n      if (collectThreats) {\n        const matches = value.match(pattern);\n        if (matches) {\n          for (const match of matches) {\n            threats.push({\n              type: 'command_injection',\n              pattern: pattern.source,\n              original: match,\n            });\n          }\n        }\n      }\n      \n      value = value.replace(pattern, ' ');\n      wasSanitized = true;\n    }\n  }\n\n  if (collectThreats) {\n    return { value, wasSanitized, threats };\n  }\n  \n  return value;\n}\n\n/**\n * Checks if a string contains command injection patterns.\n * Does not sanitize — use sanitizeCommand() for that.\n * \n * @param input - The string to check\n * @returns True if command injection patterns detected\n */\nexport function detectCommandInjection(input: string): boolean {\n  if (typeof input !== 'string') return false;\n  \n  for (const pattern of COMMAND_PATTERNS) {\n    pattern.lastIndex = 0;\n    if (pattern.test(input)) {\n      return true;\n    }\n  }\n  \n  return false;\n}\n","/**\n * @module @arcis/node/sanitizers/ssti\n * Server-Side Template Injection (SSTI) prevention\n */\n\nimport type { SanitizeResult, ThreatInfo } from '../core/types';\n\n/**\n * SSTI detection patterns (ReDoS-safe).\n *\n * Covers Jinja2, Twig, Nunjucks, Freemarker, Thymeleaf, Spring EL,\n * ERB, EJS, Pug/Jade, and Python sandbox-escape dunder chains.\n */\nconst SSTI_DETECT_PATTERNS = [\n  /** Jinja2 / Twig / Nunjucks: {{ ... }} */\n  /\\{\\{.*?\\}\\}/g,\n  /** Freemarker / Thymeleaf / Spring EL: ${ ... } */\n  /\\$\\{.*?\\}/g,\n  /** ERB / EJS: <%= ... %> or <% ... %> */\n  /<%[=\\-]?.*?%>/gs,\n  /** Pug / Jade / Slim: #{ ... } */\n  /#\\{.*?\\}/g,\n  /** Python dunder sandbox escape */\n  /__(?:class|mro|subclasses|globals|builtins|import)__/gi,\n  /** Jinja2 config leak: {{config.X}} or {{config['X']}} */\n  /\\{\\{\\s*config[.\\[]/gi,\n  /** Jinja2 built-in objects */\n  /\\{\\{\\s*(?:self|request|lipsum|cycler|joiner|namespace|range)\\b/gi,\n  /** Velocity #set/#foreach + OGNL/Velocity method calls ($rt.exec, .getRuntime). Benchmark ssti-velocity-runtime. */\n  /#set\\s*\\(\\s*\\$|#foreach\\s*\\(\\s*\\$|\\$\\w+\\.(?:exec|getClass|getRuntime|getMethod|invoke)\\b/gi,\n  /** Laravel Blade raw-PHP directive: `@php(...)` inline or `@php ... @endphp` block\n   * (the `{{ }}` Blade echo form is already covered above). Requires `@php(` or the\n   * `@endphp` close so it doesn't fire on the bare `@php` social handle. */\n  /@php\\s*\\(|@endphp\\b/gi,\n] as const;\n\n/**\n * Removal patterns — strip template expressions that look like actual attacks.\n *\n * ${ and #{ patterns are narrowed to require operators/method-calls inside to\n * avoid false-positives on JS template literals (${name}) and Ruby/Pug output\n * expressions (#{name}) that appear in legitimate user-submitted content.\n *\n * The broader detection patterns above still flag these for detectSsti() —\n * narrowing only applies to destructive sanitization.\n */\nconst SSTI_REMOVE_PATTERNS = [\n  /** Jinja2 / Twig: {{ ... }} — always strip (not valid in any JS context) */\n  /\\{\\{.*?\\}\\}/g,\n  /**\n   * Freemarker / Spring EL: ${...} — strip when expression contains operators,\n   * method calls, or Python dunder patterns (sandbox escape).\n   * Bare ${name} and ${user.name} are left intact (JS template literal syntax).\n   */\n  /\\$\\{[^}]*__\\w+__[^}]*\\}/g,\n  /\\$\\{[^}]*[?!()*+\\-/][^}]*\\}/g,\n  /** ERB / EJS: <%= ... %> */\n  /<%[=\\-]?.*?%>/gs,\n  /**\n   * Pug / Jade: #{...} — same narrowing as ${ above, plus dunder detection.\n   * #{name} output expressions are left intact.\n   */\n  /#\\{[^}]*__\\w+__[^}]*\\}/g,\n  /#\\{[^}]*[?!()*+\\-/][^}]*\\}/g,\n  /** Python dunder sandbox escape — always strip */\n  /__(?:class|mro|subclasses|globals|builtins|import)__/gi,\n] as const;\n\n/**\n * Sanitizes a string to prevent SSTI attacks.\n * Removes template expression syntax.\n */\nexport function sanitizeSsti(input: string, collectThreats?: false): string;\nexport function sanitizeSsti(input: string, collectThreats: true): SanitizeResult;\nexport function sanitizeSsti(input: string, collectThreats = false): string | SanitizeResult {\n  if (typeof input !== 'string') {\n    return collectThreats\n      ? { value: String(input), wasSanitized: false, threats: [] }\n      : String(input);\n  }\n\n  const threats: ThreatInfo[] = [];\n  let value = input;\n  let wasSanitized = false;\n\n  for (const pattern of SSTI_REMOVE_PATTERNS) {\n    pattern.lastIndex = 0;\n    if (pattern.test(value)) {\n      pattern.lastIndex = 0;\n\n      if (collectThreats) {\n        const matches = value.match(pattern);\n        if (matches) {\n          for (const match of matches) {\n            threats.push({\n              type: 'ssti',\n              pattern: pattern.source,\n              original: match,\n            });\n          }\n        }\n      }\n\n      value = value.replace(pattern, '');\n      wasSanitized = true;\n    }\n  }\n\n  if (collectThreats) {\n    return { value, wasSanitized, threats };\n  }\n\n  return value;\n}\n\n/**\n * Checks if a string contains SSTI patterns.\n * Does not sanitize — use sanitizeSsti() for that.\n *\n * @param input - The string to check\n * @returns True if SSTI patterns detected\n */\nexport function detectSsti(input: string): boolean {\n  if (typeof input !== 'string') return false;\n\n  for (const pattern of SSTI_DETECT_PATTERNS) {\n    pattern.lastIndex = 0;\n    if (pattern.test(input)) {\n      return true;\n    }\n  }\n\n  return false;\n}\n","/**\n * @module @arcis/node/sanitizers/xxe\n * XML External Entity (XXE) injection prevention\n */\n\nimport type { SanitizeResult, ThreatInfo } from '../core/types';\n\n/**\n * XXE detection patterns (ReDoS-safe).\n *\n * Covers DOCTYPE declarations, ENTITY definitions, SYSTEM/PUBLIC references,\n * parameter entities, and CDATA abuse.\n */\n/**\n * Billion-laughs defense: cap raw XML input length and the count of\n * entity references. A valid document rarely needs more than a handful of\n * entities; thousands of `&foo;` references is the classic bomb shape.\n */\nconst MAX_XXE_INPUT_BYTES = 1_000_000; // 1 MB — above any reasonable config/SOAP payload\nconst MAX_ENTITY_REFERENCES = 64;\n\nconst XXE_DETECT_PATTERNS = [\n  /** DOCTYPE declaration */\n  /<!DOCTYPE\\b/gi,\n  /** ENTITY declaration */\n  /<!ENTITY\\b/gi,\n  /** SYSTEM keyword with URI */\n  /\\bSYSTEM\\s+[\"']/gi,\n  /** PUBLIC keyword with URI */\n  /\\bPUBLIC\\s+[\"']/gi,\n  /** Parameter entity reference (%entity;) */\n  /%\\s*\\w+\\s*;/g,\n  /** CDATA section (often used to smuggle payloads) */\n  /<!\\[CDATA\\[/gi,\n] as const;\n\n/** Removal patterns — strip the dangerous XML constructs */\nconst XXE_REMOVE_PATTERNS = [\n  /** Full DOCTYPE block with optional internal subset: <!DOCTYPE ... [...]> */\n  /<!DOCTYPE\\s[^[>]*(?:\\[[^\\]]*\\]\\s*)?>|<!DOCTYPE\\s[^>]*>/gi,\n  /** Full ENTITY declaration: <!ENTITY ... > */\n  /<!ENTITY[^>]*>/gi,\n  /** CDATA sections: <![CDATA[ ... ]]> */\n  /<!\\[CDATA\\[[\\s\\S]*?\\]\\]>/gi,\n] as const;\n\n/**\n * Sanitizes a string to prevent XXE attacks.\n * Removes DOCTYPE, ENTITY, and CDATA constructs.\n */\nexport function sanitizeXxe(input: string, collectThreats?: false): string;\nexport function sanitizeXxe(input: string, collectThreats: true): SanitizeResult;\nexport function sanitizeXxe(input: string, collectThreats = false): string | SanitizeResult {\n  if (typeof input !== 'string') {\n    return collectThreats\n      ? { value: String(input), wasSanitized: false, threats: [] }\n      : String(input);\n  }\n\n  const threats: ThreatInfo[] = [];\n  let value = input;\n  let wasSanitized = false;\n\n  // Billion-laughs defense: oversize input or many entity refs → flatten to empty.\n  // Safer to discard than to attempt partial sanitization of a bomb payload.\n  if (value.length > MAX_XXE_INPUT_BYTES) {\n    if (collectThreats) {\n      threats.push({ type: 'xxe', pattern: 'oversize_input', original: `length=${value.length}` });\n    }\n    return collectThreats ? { value: '', wasSanitized: true, threats } : '';\n  }\n  const entityRefs = value.match(/&\\w+;/g);\n  if (entityRefs && entityRefs.length > MAX_ENTITY_REFERENCES) {\n    if (collectThreats) {\n      threats.push({ type: 'xxe', pattern: 'entity_expansion', original: `count=${entityRefs.length}` });\n    }\n    return collectThreats ? { value: '', wasSanitized: true, threats } : '';\n  }\n\n  for (const pattern of XXE_REMOVE_PATTERNS) {\n    pattern.lastIndex = 0;\n    if (pattern.test(value)) {\n      pattern.lastIndex = 0;\n\n      if (collectThreats) {\n        const matches = value.match(pattern);\n        if (matches) {\n          for (const match of matches) {\n            threats.push({\n              type: 'xxe',\n              pattern: pattern.source,\n              original: match,\n            });\n          }\n        }\n      }\n\n      value = value.replace(pattern, '');\n      wasSanitized = true;\n    }\n  }\n\n  if (collectThreats) {\n    return { value, wasSanitized, threats };\n  }\n\n  return value;\n}\n\n/**\n * Checks if a string contains XXE patterns.\n * Does not sanitize — use sanitizeXxe() for that.\n *\n * @param input - The string to check\n * @returns True if XXE patterns detected\n */\nexport function detectXxe(input: string): boolean {\n  if (typeof input !== 'string') return false;\n\n  for (const pattern of XXE_DETECT_PATTERNS) {\n    pattern.lastIndex = 0;\n    if (pattern.test(input)) {\n      return true;\n    }\n  }\n\n  return false;\n}\n","/**\n * @module @arcis/node/sanitizers/ldap\n * LDAP injection prevention\n *\n * LDAP special characters in filter context: * ( ) \\ NUL\n * LDAP special characters in DN context:     , + < > ; \" = / \\ NUL\n *\n * RFC 4515 (filter) and RFC 4514 (DN) define the escaping rules.\n * Sanitization escapes rather than strips — preserves the original value\n * while making it safe to embed in LDAP queries.\n */\n\n// LDAP filter special characters per RFC 4515 (single pass includes NUL).\n// Used for ESCAPING — broad set is fine here because escaping a benign\n// char is safe; the value just gets a `\\xx` representation.\nconst LDAP_FILTER_CHARS = /[*()\\\\\\x00]/g;\n\n// LDAP DN special characters per RFC 4514 (single pass includes NUL)\nconst LDAP_DN_CHARS = /[,+<>;\"=\\/\\\\\\x00*()\\x00]/g;\n\n// Wildcard-value detection: `=*` inside a filter (e.g. `(uid=*)`).\n// Real LDAP filter abuse; legitimate values don't end in `=*`.\nconst LDAP_WILDCARD_VALUE_PATTERN = /=\\s*\\*/;\n\n// NUL byte detection — used for LDAP query truncation attacks.\n// Matches both a real NUL (`\\x00`) and the literal escape sequence\n// `\\00` (backslash-zero-zero), which is how it arrives over JSON/form\n// text before any decode. Benchmark ldap-null-byte-truncate.\nconst LDAP_NUL_PATTERN = /\\x00|\\\\00/;\n\n// Detection pattern for OR/AND bypass and wildcard abuse.\n// Real shapes: `*)(uid=*` (break the filter, inject a new clause).\nconst LDAP_INJECTION_PATTERN = /\\)\\s*\\(|\\*\\s*\\)\\s*\\(/;\n\n// Detection pattern for LDAP NOT-operator bypass (improvements.md Q8).\n// Catches ')(!', '&(!', '|(!' shapes that legitimate filters never contain;\n// these are the attacker's NOT-clause appended to enumerate or exclude\n// entries (e.g. '*)(uid=*)(!(uid=admin))'). Companion to\n// LDAP_INJECTION_PATTERN; together they cover the OR-then-NOT corpus.\nconst LDAP_NOT_BYPASS_PATTERN = /\\)\\s*\\(\\s*!|&\\s*\\(\\s*!|\\|\\s*\\(\\s*!/;\n\nconst escapeChar = (char: string) => '\\\\' + char.charCodeAt(0).toString(16).padStart(2, '0');\n\n/**\n * Sanitizes a string for safe use in LDAP filter expressions.\n * Escapes * ( ) \\ and NUL per RFC 4515.\n *\n * @example\n * sanitizeLdapFilter(\"user*(admin)\")\n * // Returns: \"user\\2a\\28admin\\29\"\n */\nexport function sanitizeLdapFilter(input: string): string {\n  if (typeof input !== 'string') return String(input);\n  return input.replace(LDAP_FILTER_CHARS, escapeChar);\n}\n\n/**\n * Sanitizes a string for safe use in LDAP Distinguished Names (DN).\n * Escapes , + < > ; \" = / \\ and NUL per RFC 4514.\n *\n * @example\n * sanitizeLdapDn(\"cn=admin,dc=example\")\n * // Returns: \"cn\\3dadmin\\2cdc\\3dexample\"\n */\nexport function sanitizeLdapDn(input: string): string {\n  if (typeof input !== 'string') return String(input);\n  return input.replace(LDAP_DN_CHARS, escapeChar);\n}\n\n/**\n * Detects potential LDAP injection patterns in a string.\n * Does not sanitize — use sanitizeLdapFilter() or sanitizeLdapDn() for that.\n *\n * Designed for request-boundary scanning: matches only the specific\n * shapes real LDAP injection produces. The older broad\n * `[*()\\\\\\x00]` pattern was removed because it false-positived on\n * every markdown bold `**bold**`, every parenthesised string, every\n * apostrophe-in-name. Mirrors the `ldap-injection-strict` +\n * `ldap-not-bypass` rules from packages/core/patterns.json which are\n * marked `request_boundary_safe: true`. Benchmark FP class B2, 2026-06-07.\n *\n * @param input - The string to check\n * @returns True if LDAP injection patterns detected\n *\n * @example\n * detectLdapInjection(\"*)(uid=*))(|(uid=*\")  // true  — filter break-out\n * detectLdapInjection(\"(uid=*)\")              // true  — wildcard value\n * detectLdapInjection(\"ad\\x00min\")            // true  — NUL truncation\n * detectLdapInjection(\"**bold**\")             // false — markdown\n * detectLdapInjection(\"hello *world*\")        // false — emphasis\n * detectLdapInjection(\"john\")                 // false\n */\nexport function detectLdapInjection(input: string): boolean {\n  if (typeof input !== 'string') return false;\n  return (\n    LDAP_INJECTION_PATTERN.test(input) ||\n    LDAP_NOT_BYPASS_PATTERN.test(input) ||\n    LDAP_WILDCARD_VALUE_PATTERN.test(input) ||\n    LDAP_NUL_PATTERN.test(input)\n  );\n}\n","/**\n * @module @arcis/node/sanitizers/xpath\n * XPath injection prevention.\n *\n * XPath 1.0 has no escape syntax for string literals — the only way to\n * embed user input safely is parameterised queries / variable bindings.\n * Neither libxml2 nor most JS XPath libraries expose a canonical escape\n * function. The pragmatic answer everyone ships:\n *\n *   - Detect: scan for unescaped quotes or expression-control chars\n *     that suggest the user is trying to break out of a string literal.\n *   - Sanitize: strip the offending control characters. Lossy by design;\n *     callers that need lossless input should use parameterised queries\n *     directly.\n *\n * Detection is the load-bearing surface for this vector. Sanitization is\n * a fallback for users running existing XPath strings through user input\n * who can't switch to bound parameters today.\n */\n\n// XPath expression-control characters that an attacker uses to escape\n// a string literal: single quote, double quote, comma (changes function\n// arity), the union operator |, and parens (used in `) or (` toggles\n// against XPath function calls). These are the same shapes Aikido /\n// Snyk's xpath rules look for.\nconst XPATH_INJECTION_CHARS = /['\"|,()]/;\n\n// Common operator-injection patterns: unescaped boolean injection\n// (`' or '1'='1`), function tampering (`,`), and union (`|`).\n// Also blind-extraction functions (`substring(name(...))`,\n// `string-length(`, `count(/`) used to leak the document one char at a\n// time. Benchmark xpath-blind-substring.\nconst XPATH_INJECTION_PATTERN =\n  /('\\s*(or|and)\\s*'|\"\\s*(or|and)\\s*\"|\\)\\s*(or|and)\\s*\\(|\\|\\s*\\/|\\bsubstring\\s*\\(\\s*name\\s*\\(|\\bstring-length\\s*\\(|\\bcount\\s*\\(\\s*\\/)/i;\n\n/**\n * Detects XPath-injection-shaped patterns in a string. Returns true when\n * the input looks like it's trying to break out of an XPath string\n * literal or hijack the expression structure.\n *\n * Conservative on purpose: triggers on any control char in the input\n * combined with a boolean / union pattern. Plain user names and emails\n * (no quotes, no pipes) pass clean.\n */\nexport function detectXpathInjection(input: string): boolean {\n  if (typeof input !== 'string' || input.length === 0) return false;\n  // Fast path: skip the regex test entirely when no control chars exist.\n  if (!XPATH_INJECTION_CHARS.test(input)) return false;\n  return XPATH_INJECTION_PATTERN.test(input);\n}\n\n/**\n * Strips XPath expression-control characters from a string. Lossy —\n * `O'Brien` becomes `OBrien`. Use only when migrating legacy code that\n * concatenates user input into XPath; new code should use bound\n * parameters via the underlying XPath library.\n */\nexport function sanitizeXpath(input: string): string {\n  if (typeof input !== 'string') return String(input);\n  return input.replace(/['\"|,]/g, '');\n}\n","/**\n * @module @arcis/node/sanitizers/headers\n * HTTP Header Injection & CRLF Injection prevention\n *\n * Prevents attackers from injecting newline characters (\\r\\n) into HTTP header\n * values, which can lead to response splitting, session fixation, XSS via\n * injected headers, and cache poisoning.\n */\n\nimport type { SanitizeResult, ThreatInfo } from '../core/types';\n\n/**\n * Characters and sequences that enable header injection.\n * - \\r\\n (CRLF) — HTTP header delimiter, enables response splitting\n * - \\r, \\n alone — partial line breaks, some servers normalize to CRLF\n * - \\0 (null byte) — can truncate header values in some implementations\n */\nconst HEADER_INJECTION_PATTERN = /\\r\\n|\\r|\\n|\\0/g;\n\n/**\n * Request-boundary header-injection shape: a newline (CRLF or bare CR/LF)\n * followed by a header-name token and a colon (`\\r\\nSet-Cookie:`,\n * `\\nX-Injected:`). This is the response-splitting / header-smuggling\n * signal. Unlike HEADER_INJECTION_PATTERN it does NOT flag a bare newline,\n * so multi-line request bodies (markdown, textareas, code) pass cleanly.\n * Mirrors Python's email-header-bare-newline rule. v1.7 parity 2026-06-08.\n */\nconst HEADER_INJECTION_STRICT_PATTERN =\n  /(?:\\r\\n|\\r|\\n)\\s*[a-zA-Z][a-zA-Z0-9-]{0,40}\\s*:/;\n\n/**\n * Narrow header-injection check for request-boundary scanning. Returns\n * true only on a CRLF-then-header-name-then-colon shape, never on a bare\n * newline. Use this in `scanThreats`; use `detectHeaderInjection` (broad)\n * when sanitizing a value destined for a response header.\n */\nexport function detectHeaderInjectionStrict(input: string): boolean {\n  if (typeof input !== 'string') return false;\n  return HEADER_INJECTION_STRICT_PATTERN.test(input);\n}\n\n/**\n * Sanitizes a header value by stripping CRLF sequences, bare CR/LF, and null bytes.\n *\n * @param input - The header value to sanitize\n * @param collectThreats - Whether to collect threat information (default: false)\n * @returns Sanitized string or SanitizeResult if collectThreats is true\n *\n * @example\n * sanitizeHeaderValue(\"safe-value\")\n * // Returns: \"safe-value\"\n *\n * sanitizeHeaderValue(\"value\\r\\nX-Injected: evil\")\n * // Returns: \"valueX-Injected: evil\"\n */\nexport function sanitizeHeaderValue(input: string, collectThreats?: false): string;\nexport function sanitizeHeaderValue(input: string, collectThreats: true): SanitizeResult;\nexport function sanitizeHeaderValue(input: string, collectThreats = false): string | SanitizeResult {\n  if (typeof input !== 'string') {\n    return collectThreats\n      ? { value: String(input), wasSanitized: false, threats: [] }\n      : String(input);\n  }\n\n  const threats: ThreatInfo[] = [];\n  let wasSanitized = false;\n\n  if (HEADER_INJECTION_PATTERN.test(input)) {\n    HEADER_INJECTION_PATTERN.lastIndex = 0;\n    wasSanitized = true;\n\n    if (collectThreats) {\n      const matches = input.match(HEADER_INJECTION_PATTERN);\n      if (matches) {\n        for (const match of matches) {\n          threats.push({\n            type: 'header_injection',\n            pattern: HEADER_INJECTION_PATTERN.source,\n            original: match,\n          });\n        }\n      }\n    }\n  }\n\n  HEADER_INJECTION_PATTERN.lastIndex = 0;\n  const value = input.replace(HEADER_INJECTION_PATTERN, '');\n\n  if (collectThreats) {\n    return { value, wasSanitized, threats };\n  }\n\n  return value;\n}\n\n/**\n * Sanitizes an object of header key-value pairs.\n * Strips CRLF/null bytes from both keys and values.\n *\n * @param headers - Object with header names as keys and header values as values\n * @returns New object with sanitized header names and values\n *\n * @example\n * sanitizeHeaders({ \"X-Custom\": \"safe\", \"X-Bad\\r\\n\": \"value\\r\\ninjected\" })\n * // Returns: { \"X-Custom\": \"safe\", \"X-Bad\": \"valueinjected\" }\n */\nexport function sanitizeHeaders(headers: Record<string, string>): Record<string, string> {\n  if (!headers || typeof headers !== 'object') {\n    return {};\n  }\n\n  const result: Record<string, string> = {};\n\n  for (const [key, value] of Object.entries(headers)) {\n    const sanitizedKey = sanitizeHeaderValue(String(key));\n    const sanitizedValue = sanitizeHeaderValue(String(value));\n    result[sanitizedKey] = sanitizedValue;\n  }\n\n  return result;\n}\n\n/**\n * Checks if a string contains HTTP header injection patterns (CRLF, null bytes).\n * Does not sanitize — use sanitizeHeaderValue() for that.\n *\n * @param input - The string to check\n * @returns True if header injection patterns detected\n */\nexport function detectHeaderInjection(input: string): boolean {\n  if (typeof input !== 'string') return false;\n\n  HEADER_INJECTION_PATTERN.lastIndex = 0;\n  return HEADER_INJECTION_PATTERN.test(input);\n}\n\n/**\n * Email-header injection prevention. Same byte-level threat as HTTP\n * header injection — `\\r\\n` in a user-controlled email field\n * (`To`, `From`, `Subject`, etc.) lets an attacker inject extra headers\n * (most commonly Bcc) and pivot a contact form into a spam relay.\n *\n * Aliased to the HTTP-header sanitizers because the wire-level fix is\n * identical: strip CRLF + null bytes from the value before\n * concatenating into the header. Use these in form-to-email handlers:\n *\n * ```ts\n * const subject = sanitizeEmailHeader(req.body.subject);\n * const to = sanitizeEmailHeader(req.body.to);\n * if (detectEmailHeaderInjection(req.body.to)) reject(...);\n * ```\n */\nexport const sanitizeEmailHeader = sanitizeHeaderValue;\nexport const detectEmailHeaderInjection = detectHeaderInjection;\n","/**\n * @module @arcis/node/sanitizers/deserialization\n *\n * V33 — Modern deserialization marker detection (improvements.md §1.2).\n *\n * Detect input that LOOKS like a serialized-object payload for\n * runtimes where deserialization equals code execution: Python\n * pickle, Java FastJSON, PHP unserialize, Ruby Marshal, .NET\n * BinaryFormatter.\n *\n * Detection-only — the right response to a hit is \"refuse the\n * request\" not \"strip the bytes and pass through\" (a forgiving\n * parser might still deserialize the remainder to something\n * dangerous). Caller decides.\n *\n * Mirrors `arcis-python/arcis/sanitizers/deserialization.py`. Both\n * SDKs must accept the same base corpus per Pattern 7.\n */\n\nexport type DeserializeRuntime =\n  | 'python_pickle'\n  | 'java_fastjson'\n  | 'php_unserialize'\n  | 'ruby_marshal'\n  | 'dotnet_binary_formatter';\n\n// Python pickle: \\x80 followed by version byte 0x02-0x05.\nconst PICKLE_HEAD = /^\\x80[\\x02-\\x05]/;\n\n// Base64-encoded pickle. Attackers ship pickle over JSON/text as base64,\n// so the raw head-byte check never sees \\x80. The base64 of \\x80\\x02..05\n// always starts \"gA\" + a known char; we pre-filter cheaply, then decode\n// and re-check the head byte. Benchmark deser-python-pickle-marker.\nconst PICKLE_B64_PREFIX = /^gA[I-Z]/;\nconst B64_SHAPE = /^[A-Za-z0-9+/]{12,}={0,2}$/;\n\n// Ruby Marshal magic: \\x04\\x08 at start (Ruby 1.9+).\nconst RUBY_MARSHAL_HEAD = /^\\x04\\x08/;\n\n// .NET BinaryFormatter: 5-byte serialization-header.\nconst DOTNET_BINFMT_HEAD = /^\\x00\\x01\\x00\\x00\\x00/;\n\n// Java FastJSON: embedded `\"@type\":\"<class>\"`. Match anywhere.\nconst FASTJSON_AUTOTYPE = /\"@type\"\\s*:\\s*\"[a-zA-Z_$][\\w$.]*\"/;\n\n// PHP unserialize: `O:<len>:\"<ClassName>\":<count>:{` shape.\nconst PHP_UNSERIALIZE = /O:\\d+:\"[a-zA-Z_\\\\][\\w\\\\]*\":\\d+:\\{/;\n\n/**\n * Detect a serialized-object marker for any known runtime.\n *\n * Returns the runtime tag if a marker matches, or null if the input\n * looks safe. Precedence: head-byte markers (pickle / Ruby / .NET)\n * before embedded markers (FastJSON / PHP).\n */\nexport function detectDeserialization(\n  payload: string,\n): DeserializeRuntime | null {\n  if (typeof payload !== 'string' || payload.length === 0) {\n    return null;\n  }\n  if (PICKLE_HEAD.test(payload)) return 'python_pickle';\n  // Base64-encoded pickle: prefix pre-filter, then decode + re-check head.\n  if (PICKLE_B64_PREFIX.test(payload) && B64_SHAPE.test(payload)) {\n    try {\n      const decoded = Buffer.from(payload, 'base64');\n      if (\n        decoded.length >= 2 &&\n        decoded[0] === 0x80 &&\n        decoded[1] >= 0x02 &&\n        decoded[1] <= 0x05\n      ) {\n        return 'python_pickle';\n      }\n    } catch {\n      // not valid base64 — fall through\n    }\n  }\n  if (RUBY_MARSHAL_HEAD.test(payload)) return 'ruby_marshal';\n  if (DOTNET_BINFMT_HEAD.test(payload)) return 'dotnet_binary_formatter';\n  if (FASTJSON_AUTOTYPE.test(payload)) return 'java_fastjson';\n  if (PHP_UNSERIALIZE.test(payload)) return 'php_unserialize';\n  return null;\n}\n\n/** Convenience boolean wrapper around `detectDeserialization`. */\nexport function isSerializedPayload(payload: string): boolean {\n  return detectDeserialization(payload) !== null;\n}\n","/**\n * @module @arcis/node/sanitizers/nosql\n * NoSQL injection prevention (MongoDB operators)\n */\n\nimport { NOSQL_DANGEROUS_KEYS, NOSQL_STRING_PATTERN } from '../core/constants';\n\n/**\n * Checks if a key is a dangerous MongoDB operator.\n * \n * @param key - The key to check\n * @returns True if the key is a MongoDB operator\n * \n * @example\n * isDangerousNoSqlKey('$gt') // true\n * isDangerousNoSqlKey('name') // false\n */\nexport function isDangerousNoSqlKey(key: string): boolean {\n  return NOSQL_DANGEROUS_KEYS.has(key);\n}\n\n/**\n * Recursively checks if an object contains dangerous MongoDB operators.\n * \n * @param obj - The object to check\n * @param maxDepth - Maximum recursion depth (default: 10)\n * @returns True if dangerous operators found\n */\nexport function detectNoSqlInjection(obj: unknown, maxDepth = 10): boolean {\n  if (maxDepth <= 0) return false;\n  if (obj === null || typeof obj !== 'object') return false;\n  \n  if (Array.isArray(obj)) {\n    return obj.some(item => detectNoSqlInjection(item, maxDepth - 1));\n  }\n  \n  for (const key of Object.keys(obj as Record<string, unknown>)) {\n    if (isDangerousNoSqlKey(key)) {\n      return true;\n    }\n    \n    const value = (obj as Record<string, unknown>)[key];\n    if (typeof value === 'object' && value !== null) {\n      if (detectNoSqlInjection(value, maxDepth - 1)) {\n        return true;\n      }\n    }\n  }\n  \n  return false;\n}\n\n/**\n * Detects a MongoDB operator appearing in a STRING value.\n *\n * detectNoSqlInjection only inspects object keys. But operators also\n * arrive as strings: `?user[$ne]=1` reaches the handler as the literal\n * `$ne` before any object is built, and mongo-shell payloads like\n * `$where: '1==1'` are plain strings. This is the string-level check\n * used by block-mode scanThreats, matching Python's `_NOSQL_DETECT`.\n *\n * @param input - The string to check\n * @returns True if a NoSQL operator token is present\n *\n * @example\n * detectNoSqlString(\"$where: 'this.a==1'\") // true\n * detectNoSqlString(\"$invoice total\")      // false ($in not a token here)\n */\nexport function detectNoSqlString(input: string): boolean {\n  if (typeof input !== 'string') return false;\n  return NOSQL_STRING_PATTERN.test(input);\n}\n\n/**\n * Get list of all MongoDB operators considered dangerous.\n * Useful for documentation or custom validation.\n *\n * @returns Array of dangerous operator strings\n */\nexport function getDangerousOperators(): string[] {\n  return Array.from(NOSQL_DANGEROUS_KEYS);\n}\n","/**\n * @module @arcis/node/sanitizers/sanitize\n * Main sanitization functions that combine all sanitizers\n */\n\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\nimport { INPUT, DANGEROUS_PROTO_KEYS, NOSQL_DANGEROUS_KEYS, AUTH_FIELDS } from '../core/constants';\nimport { InputTooLargeError, SecurityThreatError } from '../core/errors';\nimport type { SanitizeOptions } from '../core/types';\nimport { sanitizeXss, detectXss } from './xss';\nimport { sanitizeSql, detectSql } from './sql';\nimport { sanitizePath, detectPathTraversal } from './path';\nimport { sanitizeCommand, detectCommandInjection } from './command';\nimport { detectSsti } from './ssti';\nimport { detectXxe } from './xxe';\nimport { detectLdapInjection } from './ldap';\nimport { detectXpathInjection } from './xpath';\nimport { detectHeaderInjectionStrict } from './headers';\nimport { detectDeserialization } from './deserialization';\nimport { detectNoSqlString } from './nosql';\n\n/**\n * Sanitize a string value against multiple attack vectors.\n * \n * Order matters: We do XSS encoding LAST because:\n * 1. Other sanitizers need to see the original patterns (e.g., SQL keywords)\n * 2. HTML encoding is the final safe output transformation\n * 3. Encoded entities like &lt; shouldn't be treated as SQL/command threats\n * \n * @param value - The string to sanitize\n * @param options - Sanitization options\n * @returns The sanitized string\n * \n * @example\n * sanitizeString(\"<script>alert('xss')</script>\")\n * // Returns: \"&lt;script&gt;alert(&#x27;xss&#x27;)&lt;/script&gt;\"\n * \n * @example\n * sanitizeString(\"../../etc/passwd\")\n * // Returns: \"etc/passwd\"\n */\n/**\n * Decode URL + HTML entity layers until the string is stable.\n *\n * improvements.md §1.1.b — closes the encoding-stack bypass class.\n * A payload like `%2526%2523x3c%253bscript%2526%2523x3e%253b` is a\n * triple-encoded `<script>`: pass 1 URL-decodes to\n * `%26%23x3c%3bscript%26%23x3e%3b`, pass 2 URL-decodes to\n * `&#x3c;script&#x3e;`, pass 3 HTML-decodes to `<script>`. Without\n * this helper the literal ASCII `<script>` never appears in the\n * string, so the XSS regex never fires.\n *\n * Bounded at 4 passes to prevent pathological-input loops. Base64\n * decoding is intentionally NOT in the chain — false-positive rate\n * on arbitrary text would be high.\n */\nfunction multiDecode(value: string, maxPasses = 4): string {\n  for (let i = 0; i < maxPasses; i++) {\n    const prev = value;\n\n    // URL-decode. decodeURIComponent throws on malformed sequences\n    // (lone `%` with no hex pair); treat that as \"no further\n    // URL-decoding possible\" and continue with the current value.\n    try {\n      value = decodeURIComponent(value);\n    } catch {\n      // leave value as-is\n    }\n\n    // HTML entity decode. No built-in in Node, so inline the common\n    // entities here. Numeric (`&#NN;`, `&#xHH;`) covers the bulk of\n    // XSS-encoding tricks; the five named entities below cover the\n    // rest of the encoding-bypass test corpus.\n    value = htmlEntityDecode(value);\n\n    if (value === prev) break;\n  }\n  return value;\n}\n\n/** Decode HTML entities — numeric (decimal + hex) plus the five core\n * named entities that XSS payloads use. Keeps the dep-free zero-dep\n * footprint of `@arcis/node`. */\nfunction htmlEntityDecode(s: string): string {\n  // &#NN; decimal numeric\n  s = s.replace(/&#(\\d+);/g, (_m, n) => {\n    const code = parseInt(n, 10);\n    return Number.isFinite(code) && code >= 0 && code <= 0x10ffff\n      ? String.fromCodePoint(code)\n      : _m;\n  });\n  // &#xHH; or &#XHH; hex numeric\n  s = s.replace(/&#x([0-9a-fA-F]+);/g, (_m, h) => {\n    const code = parseInt(h, 16);\n    return Number.isFinite(code) && code >= 0 && code <= 0x10ffff\n      ? String.fromCodePoint(code)\n      : _m;\n  });\n  // The five named entities that matter for XSS detection.\n  const named: Record<string, string> = {\n    '&lt;': '<',\n    '&gt;': '>',\n    '&amp;': '&',\n    '&quot;': '\"',\n    '&apos;': \"'\",\n    '&nbsp;': ' ',\n  };\n  for (const [entity, ch] of Object.entries(named)) {\n    s = s.split(entity).join(ch);\n  }\n  return s;\n}\n\nexport function sanitizeString(value: string, options: SanitizeOptions = {}): string {\n  if (typeof value !== 'string') return value;\n\n  // Input size limit to prevent DoS\n  const maxSize = options.maxSize ?? INPUT.DEFAULT_MAX_SIZE;\n  if (value.length > maxSize) {\n    throw new InputTooLargeError(maxSize, value.length);\n  }\n\n  // Default mode is 'sanitize' (strip threats and return cleaned string).\n  // Pass mode: 'reject' to throw SecurityThreatError instead of stripping.\n  const reject = options.mode === 'reject';\n\n  // SECURITY: Normalize Unicode to NFKC BEFORE every detector runs.\n  // Fullwidth glyphs (`＜script＞`, `１+１＝２`) collapse to their ASCII\n  // equivalents, closing the entire fullwidth-bypass class for XSS,\n  // SQL, command-injection, and path-traversal in a single pass.\n  // improvements.md §1.1.a. Bypass example closed:\n  //   `＜script＞alert(1)＜/script＞`  →  `<script>alert(1)</script>`\n  let result = value.normalize('NFKC');\n\n  // SECURITY: Multi-pass URL + HTML decode (improvements.md §1.1.b).\n  // Closes the encoding-stack bypass class. After NFKC,\n  // `%2526%2523x3c%253bscript%2526%2523x3e%253b` (triple-encoded\n  // `<script>`) decodes all the way to `<script>` and hits the\n  // normal XSS strip below. Bounded at 4 passes.\n  result = multiDecode(result);\n\n  // 1. SQL injection\n  if (options.sql !== false) {\n    if (reject) {\n      if (detectSql(result)) {\n        throw new SecurityThreatError('sql_injection', 'SQL pattern detected in input');\n      }\n    } else {\n      result = sanitizeSql(result);\n    }\n  }\n\n  // 2. Path traversal prevention\n  if (options.path !== false) {\n    result = sanitizePath(result);\n  }\n\n  // 3. Command injection\n  if (options.command !== false) {\n    if (reject) {\n      if (detectCommandInjection(result)) {\n        throw new SecurityThreatError('command_injection', 'Shell metacharacter detected in input');\n      }\n    } else {\n      result = sanitizeCommand(result);\n    }\n  }\n\n  // 4. XSS stripping — always runs to remove dangerous patterns.\n  // HTML encoding is opt-in via options.htmlEncode (for SSR contexts only).\n  if (options.xss !== false) {\n    result = sanitizeXss(result, false, options.htmlEncode ?? false);\n  }\n\n  return result;\n}\n\n/**\n * Sanitize an object recursively, including nested objects and arrays.\n * Also removes prototype pollution and NoSQL injection keys.\n * \n * @param obj - The object to sanitize\n * @param options - Sanitization options\n * @returns The sanitized object\n */\nexport function sanitizeObject(obj: unknown, options: SanitizeOptions = {}): unknown {\n  if (obj === null || obj === undefined) return obj;\n  if (typeof obj === 'string') return sanitizeString(obj, options);\n  if (typeof obj !== 'object') return obj;\n  if (Array.isArray(obj)) return obj.map(item => sanitizeObject(item, options));\n\n  const result = sanitizeObjectDepth(obj as Record<string, unknown>, options, 0);\n  return options.freeze ? Object.freeze(result) : result;\n}\n\n/**\n * Internal recursive sanitization with depth tracking.\n */\nfunction sanitizeObjectDepth(\n  obj: Record<string, unknown>,\n  options: SanitizeOptions,\n  depth: number\n): Record<string, unknown> {\n  if (depth >= INPUT.MAX_RECURSION_DEPTH) return obj;\n\n  const result: Record<string, unknown> = {};\n\n  for (const key of Object.keys(obj)) {\n    // Prototype pollution protection - always block dangerous keys (case-insensitive)\n    if (options.proto !== false && DANGEROUS_PROTO_KEYS.has(key.toLowerCase())) {\n      continue;\n    }\n\n    // NoSQL injection - skip dangerous MongoDB operators in keys\n    if (options.nosql !== false && NOSQL_DANGEROUS_KEYS.has(key)) {\n      continue;\n    }\n\n    // Sanitize the key against all active threat vectors (not just XSS).\n    // Keys can carry injection payloads that bubble into query builders or ORMs.\n    const sanitizedKey = sanitizeString(key, options);\n\n    // Recursively sanitize value\n    const value = obj[key];\n    if (value === null || value === undefined) {\n      result[sanitizedKey] = value;\n    } else if (typeof value === 'string') {\n      result[sanitizedKey] = sanitizeString(value, options);\n    } else if (Array.isArray(value)) {\n      result[sanitizedKey] = value.map(item => sanitizeObject(item, options));\n    } else if (typeof value === 'object') {\n      result[sanitizedKey] = sanitizeObjectDepth(value as Record<string, unknown>, options, depth + 1);\n    } else {\n      result[sanitizedKey] = value;\n    }\n  }\n\n  return result;\n}\n\n/** Threat triple returned from scanThreats. */\nexport interface ThreatHit {\n  vector:\n    | 'xss'\n    | 'sql'\n    | 'nosql'\n    | 'path'\n    | 'command'\n    | 'prototype'\n    | 'ssti'\n    | 'xxe'\n    | 'ldap'\n    | 'xpath'\n    | 'header'\n    | 'deserialization';\n  rule: string;\n  matchedPattern: string;\n}\n\n/**\n * Walk a value (string, array, or object) and return the first threat hit\n * found. Used by block-mode middleware to attribute the deny decision.\n *\n * Vector ordering matches Python's scan_threats for cross-SDK parity.\n */\nexport function scanThreats(data: unknown, depth = 0): ThreatHit | null {\n  if (depth > INPUT.MAX_RECURSION_DEPTH) return null;\n\n  if (data && typeof data === 'object' && !Array.isArray(data)) {\n    for (const key of Object.keys(data as Record<string, unknown>)) {\n      const lower = key.toLowerCase();\n      if (DANGEROUS_PROTO_KEYS.has(lower)) {\n        return { vector: 'prototype', rule: 'prototype/match', matchedPattern: key };\n      }\n      if (NOSQL_DANGEROUS_KEYS.has(key)) {\n        return { vector: 'nosql', rule: 'nosql/match', matchedPattern: key };\n      }\n      const value = (data as Record<string, unknown>)[key];\n      // NoSQL type-juggling: an auth/identity field whose value is an\n      // ARRAY instead of a scalar (e.g. {\"username\":[\"admin\"]}). MongoDB\n      // turns the array into an $in-style operator, bypassing string\n      // equality. Only arrays are flagged: operator-objects ({\"$ne\":...})\n      // are caught by NOSQL_DANGEROUS_KEYS, and a plain nested object under\n      // an auth field is legitimate. Benchmark nosql-mongo-type-juggle.\n      if (AUTH_FIELDS.has(lower) && Array.isArray(value)) {\n        return { vector: 'nosql', rule: 'nosql/type-juggle', matchedPattern: key };\n      }\n      const inner = scanThreats(value, depth + 1);\n      if (inner) return inner;\n    }\n    return null;\n  }\n\n  if (Array.isArray(data)) {\n    for (const item of data) {\n      const inner = scanThreats(item, depth + 1);\n      if (inner) return inner;\n    }\n    return null;\n  }\n\n  if (typeof data !== 'string') return null;\n\n  // SECURITY: normalize the SAME way sanitizeString does before any\n  // detector runs, so block-mode detection honors the NFKC + multi-decode\n  // bypass protection. Without this, block mode missed fullwidth\n  // `<script>` (U+FF1C), `%3Cscript%3E`, and HTML-entity-encoded payloads\n  // that sanitize-mode already caught. (v1.7 parity fix 2026-06-08.)\n  const norm = multiDecode(data.normalize('NFKC'));\n\n  const sample = norm.slice(0, 80);\n  // __proto__ as a STRING VALUE (e.g. [\"__proto__\",\"isAdmin\"] gadget-chain\n  // path array). The key-based check above only sees object keys; a dunder\n  // proto token as a value is the array-form signal. Only the dunder forms\n  // (never legit prose) are flagged, so the words \"constructor\"/\"prototype\"\n  // in normal text don't trip it. Benchmark proto-pollution-array-index.\n  if (norm.includes('__proto__')) {\n    return { vector: 'prototype', rule: 'prototype/match', matchedPattern: sample };\n  }\n  if (detectXss(norm)) {\n    return { vector: 'xss', rule: 'xss/match', matchedPattern: sample };\n  }\n  if (detectSsti(norm)) {\n    return { vector: 'ssti', rule: 'ssti/match', matchedPattern: sample };\n  }\n  if (detectXxe(norm)) {\n    return { vector: 'xxe', rule: 'xxe/match', matchedPattern: sample };\n  }\n  // Deserialization markers (pickle incl. base64, Ruby Marshal, .NET,\n  // FastJSON, PHP). Wired into block mode in v1.7 (was detection-only).\n  const deser = detectDeserialization(norm);\n  if (deser) {\n    return { vector: 'deserialization', rule: `deserialization/${deser}`, matchedPattern: sample };\n  }\n  if (detectSql(norm)) {\n    return { vector: 'sql', rule: 'sql/match', matchedPattern: sample };\n  }\n  // Path detection runs on the RAW string so the encoded-form patterns\n  // (%C0%AE overlong UTF-8, %2e%2e, %252f) still fire; multiDecode would\n  // otherwise strip them. The decoded `../` form survives in raw too.\n  if (detectPathTraversal(data) || detectPathTraversal(norm)) {\n    return { vector: 'path', rule: 'path/match', matchedPattern: sample };\n  }\n  if (detectCommandInjection(norm)) {\n    return { vector: 'command', rule: 'command/match', matchedPattern: sample };\n  }\n  // LDAP + XPath checks come AFTER command/path so a string that's\n  // primarily a path-traversal payload (`../`) gets attributed to\n  // path, not LDAP (the `\\` in `..\\..\\` would otherwise hit the LDAP\n  // backslash filter).\n  if (detectLdapInjection(norm)) {\n    return { vector: 'ldap', rule: 'ldap/match', matchedPattern: sample };\n  }\n  if (detectXpathInjection(norm)) {\n    return { vector: 'xpath', rule: 'xpath/match', matchedPattern: sample };\n  }\n  // Header injection (HTTP response splitting + email-header injection\n  // share the same byte-level threat: CRLF in a value that gets\n  // concatenated into a header). Last in the chain so the more-specific\n  // detectors (xss / sql / etc.) win on input that's both — e.g. an XSS\n  // payload with a stray newline still attributes to xss.\n  if (detectHeaderInjectionStrict(norm)) {\n    return { vector: 'header', rule: 'header/match', matchedPattern: sample };\n  }\n  // String-form NoSQL operator (`$where`, `$ne`, `[$gt]`) carried in a\n  // string value rather than an object key. Last in the chain so the\n  // more-specific detectors above win; this only catches operator tokens\n  // that would otherwise pass through. Closes the Node-vs-Python NoSQL\n  // string parity gap (GoTestWAF NoSQL was 0% on Node).\n  if (detectNoSqlString(norm)) {\n    return { vector: 'nosql', rule: 'nosql/string', matchedPattern: sample };\n  }\n  return null;\n}\n\n/**\n * Create Express middleware for request sanitization.\n * Sanitizes req.body, req.query, and req.params.\n * \n * @param options - Sanitization options\n * @returns Express middleware\n * \n * @example\n * app.use(createSanitizer());\n * \n * @example\n * app.use(createSanitizer({ xss: true, sql: true, nosql: true }));\n */\nexport function createSanitizer(options: SanitizeOptions = {}): RequestHandler {\n  return (req: Request, res: Response, next: NextFunction) => {\n    try {\n      // Block mode: scan first, return 403 on threat. The telemetry emitter\n      // reads the marker on res.finish to attribute the deny decision.\n      if (options.block) {\n        const hit =\n          scanThreats(req.body) ||\n          scanThreats(req.query) ||\n          scanThreats(req.params) ||\n          scanThreats(req.path);\n        if (hit) {\n          req.__arcis = {\n            vector: hit.vector,\n            rule: hit.rule,\n            severity: 'high',\n            matchedPattern: hit.matchedPattern,\n            reason: `${hit.vector} pattern detected in request`,\n            decision: 'deny',\n          };\n          res.status(403).json({\n            error: 'Request blocked for security reasons',\n            code: 'SECURITY_THREAT',\n            vector: hit.vector,\n          });\n          return;\n        }\n      }\n\n      if (req.body && typeof req.body === 'object') {\n        req.body = sanitizeObject(req.body, options);\n      }\n      if (req.query && typeof req.query === 'object') {\n        const sanitizedQuery = sanitizeObject(req.query, options);\n        // Express 5: req.query is a getter with no setter — override on instance\n        Object.defineProperty(req, 'query', { value: sanitizedQuery, writable: true, configurable: true });\n      }\n      if (req.params && typeof req.params === 'object') {\n        const sanitizedParams = sanitizeObject(req.params, options);\n        Object.defineProperty(req, 'params', { value: sanitizedParams, writable: true, configurable: true });\n      }\n      next();\n    } catch (err) {\n      next(err);\n    }\n  };\n}\n","/**\n * @module @arcis/node/sanitizers/prototype\n * Prototype pollution prevention\n */\n\nimport { DANGEROUS_PROTO_KEYS } from '../core/constants';\n\n/**\n * Checks if a key is dangerous for prototype pollution.\n * Case-insensitive — catches __PROTO__, Constructor, etc.\n *\n * @param key - The key to check\n * @returns True if the key could cause prototype pollution\n *\n * @example\n * isDangerousProtoKey('__proto__')   // true\n * isDangerousProtoKey('__PROTO__')   // true\n * isDangerousProtoKey('Constructor') // true\n * isDangerousProtoKey('name')        // false\n */\nexport function isDangerousProtoKey(key: string): boolean {\n  return DANGEROUS_PROTO_KEYS.has(key.toLowerCase());\n}\n\n/**\n * Recursively checks if an object contains prototype pollution keys.\n * \n * @param obj - The object to check\n * @param maxDepth - Maximum recursion depth (default: 10)\n * @returns True if dangerous keys found\n */\nexport function detectPrototypePollution(obj: unknown, maxDepth = 10): boolean {\n  if (maxDepth <= 0) return false;\n  if (obj === null || typeof obj !== 'object') return false;\n  \n  if (Array.isArray(obj)) {\n    return obj.some(item => detectPrototypePollution(item, maxDepth - 1));\n  }\n  \n  for (const key of Object.keys(obj as Record<string, unknown>)) {\n    if (DANGEROUS_PROTO_KEYS.has(key.toLowerCase())) {\n      return true;\n    }\n    \n    const value = (obj as Record<string, unknown>)[key];\n    if (typeof value === 'object' && value !== null) {\n      if (detectPrototypePollution(value, maxDepth - 1)) {\n        return true;\n      }\n    }\n  }\n  \n  return false;\n}\n\n/**\n * Get list of all keys considered dangerous for prototype pollution.\n * Useful for documentation or custom validation.\n * \n * @returns Array of dangerous key strings\n */\nexport function getDangerousProtoKeys(): string[] {\n  return Array.from(DANGEROUS_PROTO_KEYS);\n}\n","/**\n * @module @arcis/node/sanitizers/jsonp\n * JSONP callback sanitization to prevent XSS via callback parameters\n */\n\n/**\n * Valid JSONP callback pattern: only alphanumeric, underscore, dollar, and dot.\n * Bracket notation is rejected — it enables bypasses like `cb[x` (unbalanced)\n * and isn't needed for real-world JSONP callbacks.\n */\nconst SAFE_CALLBACK_PATTERN = /^[a-zA-Z_$][a-zA-Z0-9_$.]*$/;\n\n/**\n * Dangerous patterns that should never appear in a callback name,\n * even if they technically match the safe pattern.\n */\nconst DANGEROUS_CALLBACK_PATTERNS = [\n  /\\.\\./,        // prototype chain traversal\n] as const;\n\n/**\n * Validates and sanitizes a JSONP callback parameter.\n *\n * Returns the callback name if safe, or null if the callback is dangerous.\n * Use this to validate `?callback=` query parameters before wrapping responses.\n *\n * @param callback - The callback parameter value\n * @param maxLength - Maximum allowed length (default: 128)\n * @returns The safe callback name, or null if invalid\n *\n * @example\n * ```ts\n * const cb = sanitizeJsonpCallback(req.query.callback);\n * if (cb) {\n *   res.set('Content-Type', 'application/javascript');\n *   res.send(`${cb}(${JSON.stringify(data)})`);\n * } else {\n *   res.status(400).json({ error: 'Invalid callback' });\n * }\n * ```\n */\nexport function sanitizeJsonpCallback(callback: string, maxLength = 128): string | null {\n  if (typeof callback !== 'string' || callback.length === 0) {\n    return null;\n  }\n\n  if (callback.length > maxLength) {\n    return null;\n  }\n\n  if (!SAFE_CALLBACK_PATTERN.test(callback)) {\n    return null;\n  }\n\n  for (const pattern of DANGEROUS_CALLBACK_PATTERNS) {\n    if (pattern.test(callback)) {\n      return null;\n    }\n  }\n\n  return callback;\n}\n\n/**\n * Checks if a JSONP callback parameter contains potentially dangerous content.\n *\n * @param callback - The callback parameter value\n * @returns True if the callback is dangerous / invalid\n */\nexport function detectJsonpInjection(callback: string): boolean {\n  if (typeof callback !== 'string' || callback.length === 0) {\n    return false;\n  }\n\n  // If it doesn't match the safe pattern, it's potentially dangerous\n  if (!SAFE_CALLBACK_PATTERN.test(callback)) {\n    return true;\n  }\n\n  for (const pattern of DANGEROUS_CALLBACK_PATTERNS) {\n    if (pattern.test(callback)) {\n      return true;\n    }\n  }\n\n  return false;\n}\n","/**\n * @module @arcis/node/sanitizers/pii\n * PII (Personally Identifiable Information) detection and redaction\n *\n * Detects: email addresses, phone numbers, credit card numbers, SSNs, IP addresses\n */\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\nexport type PiiType = 'email' | 'phone' | 'credit_card' | 'ssn' | 'ip_address';\n\nexport interface PiiMatch {\n  type: PiiType;\n  value: string;\n  start: number;\n  end: number;\n}\n\nexport interface PiiScanOptions {\n  /** PII types to scan for. Default: all types */\n  types?: PiiType[];\n}\n\nexport interface PiiRedactOptions extends PiiScanOptions {\n  /** Replacement for redacted values. Default: '[REDACTED]' */\n  replacement?: string;\n  /** Use type-specific replacements like '[EMAIL]', '[SSN]'. Default: false */\n  typeLabels?: boolean;\n}\n\n// ─── Patterns ────────────────────────────────────────────────────────────────\n\n// Email: simplified RFC 5322 — catches real-world emails without ReDoS risk\nconst EMAIL_RE = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z]{2,})+/g;\n\n// US phone numbers: (xxx) xxx-xxxx, xxx-xxx-xxxx, xxx.xxx.xxxx, xxx xxx xxxx, +1xxxxxxxxxx\n// (?<!\\d) / (?!\\d) boundaries prevent false positives inside longer digit\n// sequences like ZIP+number combos (\"94102 555-1234\") or bank account strings.\nconst PHONE_RE = /(?<!\\d)(?:\\+?1[-.\\s]?)?\\(?[2-9]\\d{2}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}(?!\\d)/g;\n\n// Credit cards: 13-19 digits with optional separators (spaces or dashes)\nconst CREDIT_CARD_RE = /\\b(?:\\d[ -]*?){13,19}\\b/g;\n\n// SSN: XXX-XX-XXXX (with dashes or spaces)\nconst SSN_RE = /\\b\\d{3}[-\\s]\\d{2}[-\\s]\\d{4}\\b/g;\n\n// IPv4 addresses\nconst IPV4_RE = /\\b(?:(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\b/g;\n\n// IPv6 addresses (simplified — full addresses and common abbreviations)\nconst IPV6_RE = /\\b(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\\b|\\b(?:[0-9a-fA-F]{1,4}:){1,7}:|::(?:[0-9a-fA-F]{1,4}:){0,5}[0-9a-fA-F]{1,4}\\b/g;\n\nconst PATTERN_MAP: Record<PiiType, RegExp[]> = {\n  email: [EMAIL_RE],\n  phone: [PHONE_RE],\n  credit_card: [CREDIT_CARD_RE],\n  ssn: [SSN_RE],\n  ip_address: [IPV4_RE, IPV6_RE],\n};\n\nconst ALL_TYPES: PiiType[] = ['email', 'phone', 'credit_card', 'ssn', 'ip_address'];\n\nconst TYPE_LABELS: Record<PiiType, string> = {\n  email: '[EMAIL]',\n  phone: '[PHONE]',\n  credit_card: '[CREDIT_CARD]',\n  ssn: '[SSN]',\n  ip_address: '[IP_ADDRESS]',\n};\n\n// ─── Luhn Check ──────────────────────────────────────────────────────────────\n\n/**\n * Validate a credit card number using the Luhn algorithm.\n * Strips spaces and dashes before checking.\n */\nfunction luhnCheck(value: string): boolean {\n  const digits = value.replace(/[\\s-]/g, '');\n  if (!/^\\d{13,19}$/.test(digits)) return false;\n\n  let sum = 0;\n  let alternate = false;\n  for (let i = digits.length - 1; i >= 0; i--) {\n    let n = parseInt(digits[i], 10);\n    if (alternate) {\n      n *= 2;\n      if (n > 9) n -= 9;\n    }\n    sum += n;\n    alternate = !alternate;\n  }\n  return sum % 10 === 0;\n}\n\n// ─── Core Functions ──────────────────────────────────────────────────────────\n\n/**\n * Scan a string for PII and return all matches.\n *\n * @param input - String to scan\n * @param options - Optional scan configuration\n * @returns Array of PII matches with type, value, and position\n *\n * @example\n * scanPii('Call me at 555-123-4567 or email john@example.com')\n * // [\n * //   { type: 'phone', value: '555-123-4567', start: 11, end: 23 },\n * //   { type: 'email', value: 'john@example.com', start: 33, end: 49 }\n * // ]\n */\nexport function scanPii(input: string, options: PiiScanOptions = {}): PiiMatch[] {\n  if (!input || typeof input !== 'string') return [];\n\n  const types = options.types ?? ALL_TYPES;\n  const matches: PiiMatch[] = [];\n\n  for (const type of types) {\n    const patterns = PATTERN_MAP[type];\n    if (!patterns) continue;\n\n    for (const pattern of patterns) {\n      const re = new RegExp(pattern.source, pattern.flags);\n      let match: RegExpExecArray | null;\n\n      while ((match = re.exec(input)) !== null) {\n        const value = match[0];\n\n        // Credit card: validate with Luhn algorithm\n        if (type === 'credit_card' && !luhnCheck(value)) continue;\n\n        // SSN: reject invalid ranges (000, 666, 900-999 for area)\n        if (type === 'ssn') {\n          const area = parseInt(value.substring(0, 3), 10);\n          if (area === 0 || area === 666 || area >= 900) continue;\n        }\n\n        matches.push({\n          type,\n          value,\n          start: match.index,\n          end: match.index + value.length,\n        });\n      }\n    }\n  }\n\n  // Sort by position\n  matches.sort((a, b) => a.start - b.start);\n  return matches;\n}\n\n/**\n * Check if a string contains any PII.\n *\n * @param input - String to check\n * @param options - Optional scan configuration\n * @returns true if PII is detected\n */\nexport function detectPii(input: string, options: PiiScanOptions = {}): boolean {\n  return scanPii(input, options).length > 0;\n}\n\n/**\n * Redact PII from a string, replacing matches with a placeholder.\n *\n * @param input - String to redact\n * @param options - Redaction options\n * @returns String with PII replaced\n *\n * @example\n * redactPii('Email: john@example.com, SSN: 123-45-6789')\n * // 'Email: [REDACTED], SSN: [REDACTED]'\n *\n * redactPii('Email: john@example.com', { typeLabels: true })\n * // 'Email: [EMAIL]'\n */\nexport function redactPii(input: string, options: PiiRedactOptions = {}): string {\n  if (!input || typeof input !== 'string') return input;\n\n  const matches = scanPii(input, options);\n  if (matches.length === 0) return input;\n\n  const replacement = options.replacement ?? '[REDACTED]';\n\n  // Replace from end to preserve positions\n  let result = input;\n  for (let i = matches.length - 1; i >= 0; i--) {\n    const m = matches[i];\n    const label = options.typeLabels ? TYPE_LABELS[m.type] : replacement;\n    result = result.substring(0, m.start) + label + result.substring(m.end);\n  }\n\n  return result;\n}\n\n/**\n * Scan an object's string values for PII recursively.\n *\n * @param obj - Object to scan\n * @param options - Optional scan configuration\n * @returns Array of PII matches with the field path prepended\n */\nexport function scanObjectPii(\n  obj: Record<string, unknown>,\n  options: PiiScanOptions = {},\n  path = '',\n): (PiiMatch & { field: string })[] {\n  const results: (PiiMatch & { field: string })[] = [];\n  if (!obj || typeof obj !== 'object') return results;\n\n  for (const [key, value] of Object.entries(obj)) {\n    const fieldPath = path ? `${path}.${key}` : key;\n\n    if (typeof value === 'string') {\n      const matches = scanPii(value, options);\n      for (const m of matches) {\n        results.push({ ...m, field: fieldPath });\n      }\n    } else if (value && typeof value === 'object' && !Array.isArray(value)) {\n      results.push(...scanObjectPii(value as Record<string, unknown>, options, fieldPath));\n    } else if (Array.isArray(value)) {\n      for (let i = 0; i < value.length; i++) {\n        const item = value[i];\n        if (typeof item === 'string') {\n          const matches = scanPii(item, options);\n          for (const m of matches) {\n            results.push({ ...m, field: `${fieldPath}[${i}]` });\n          }\n        } else if (item && typeof item === 'object') {\n          results.push(...scanObjectPii(item as Record<string, unknown>, options, `${fieldPath}[${i}]`));\n        }\n      }\n    }\n  }\n\n  return results;\n}\n\n/**\n * Redact PII from all string values in an object recursively.\n *\n * @param obj - Object to redact\n * @param options - Redaction options\n * @returns New object with PII redacted\n */\nexport function redactObjectPii<T extends Record<string, unknown>>(\n  obj: T,\n  options: PiiRedactOptions = {},\n): T {\n  if (!obj || typeof obj !== 'object') return obj;\n\n  const result: Record<string, unknown> = {};\n\n  for (const [key, value] of Object.entries(obj)) {\n    if (typeof value === 'string') {\n      result[key] = redactPii(value, options);\n    } else if (Array.isArray(value)) {\n      result[key] = value.map(item => {\n        if (typeof item === 'string') return redactPii(item, options);\n        if (item && typeof item === 'object') return redactObjectPii(item as Record<string, unknown>, options);\n        return item;\n      });\n    } else if (value && typeof value === 'object') {\n      result[key] = redactObjectPii(value as Record<string, unknown>, options);\n    } else {\n      result[key] = value;\n    }\n  }\n\n  return result as T;\n}\n","/**\n * @module @arcis/node/sanitizers/encode\n * Context-aware output encoding for XSS prevention.\n *\n * Wrong-context encoding is the #1 cause of XSS bypasses in \"protected\" apps.\n * A single sanitize() is not enough when output goes to JS, CSS, or attribute contexts.\n */\n\n// HTML entity map — covers the 5 dangerous chars in HTML body context\nconst HTML_ENTITIES: Record<string, string> = {\n  '&': '&amp;',\n  '<': '&lt;',\n  '>': '&gt;',\n  '\"': '&quot;',\n  \"'\": '&#x27;',\n};\n\nconst HTML_ENCODE_RE = /[&<>\"']/g;\n\n/**\n * Encodes for HTML body context. Entity-encodes & < > \" '\n *\n * Use when outputting to HTML element content:\n *   `<p>${encodeForHtml(userInput)}</p>`\n */\nexport function encodeForHtml(value: string): string {\n  if (!value) return '';\n  return value.replace(HTML_ENCODE_RE, (ch) => HTML_ENTITIES[ch]);\n}\n\n/**\n * Encodes for HTML attribute context.\n * All non-alphanumeric characters are encoded as `&#xHH;` hex entities.\n *\n * Use when outputting to HTML attributes:\n *   `<div title=\"${encodeForAttribute(userInput)}\">`\n */\nexport function encodeForAttribute(value: string): string {\n  if (!value) return '';\n  let result = '';\n  for (let i = 0; i < value.length; i++) {\n    const ch = value.charCodeAt(i);\n    // Allow a-z A-Z 0-9\n    if (\n      (ch >= 0x30 && ch <= 0x39) || // 0-9\n      (ch >= 0x41 && ch <= 0x5a) || // A-Z\n      (ch >= 0x61 && ch <= 0x7a)    // a-z\n    ) {\n      result += value[i];\n    } else {\n      result += `&#x${ch.toString(16).toUpperCase()};`;\n    }\n  }\n  return result;\n}\n\n/**\n * Encodes for JavaScript string context.\n * Non-alphanumeric characters are escaped as `\\xHH` (ASCII) or `\\uHHHH` (Unicode).\n *\n * Use when embedding in JS string literals:\n *   `var x = '${encodeForJs(userInput)}';`\n */\nexport function encodeForJs(value: string): string {\n  if (!value) return '';\n  let result = '';\n  // Use for-of to iterate codepoints, not UTF-16 code units.\n  // This correctly handles surrogate pairs (emoji, symbols outside BMP).\n  for (const char of value) {\n    const cp = char.codePointAt(0);\n    if (cp === undefined) continue;\n    // Allow a-z A-Z 0-9\n    if (\n      (cp >= 0x30 && cp <= 0x39) || // 0-9\n      (cp >= 0x41 && cp <= 0x5a) || // A-Z\n      (cp >= 0x61 && cp <= 0x7a)    // a-z\n    ) {\n      result += char;\n    } else if (cp < 0x100) {\n      result += `\\\\x${cp.toString(16).toUpperCase().padStart(2, '0')}`;\n    } else if (cp <= 0xFFFF) {\n      result += `\\\\u${cp.toString(16).toUpperCase().padStart(4, '0')}`;\n    } else {\n      // Codepoints above BMP — use ES6 Unicode escape\n      result += `\\\\u{${cp.toString(16).toUpperCase()}}`;\n    }\n  }\n  return result;\n}\n\n/**\n * Encodes for URL parameter context. Percent-encodes all non-unreserved chars.\n *\n * Use when building query strings:\n *   `?q=${encodeForUrl(userInput)}`\n */\nexport function encodeForUrl(value: string): string {\n  if (!value) return '';\n  // encodeURIComponent handles most cases but doesn't encode: ! ' ( ) *\n  // We encode these additionally for full safety per RFC 3986\n  return encodeURIComponent(value).replace(/[!'()*]/g, (ch) => {\n    return `%${ch.charCodeAt(0).toString(16).toUpperCase()}`;\n  });\n}\n\n/**\n * Encodes for CSS value context.\n * Non-alphanumeric characters are hex-escaped as `\\HH ` (trailing space per CSS spec).\n *\n * Use when embedding in CSS values:\n *   `content: '${encodeForCss(userInput)}';`\n */\nexport function encodeForCss(value: string): string {\n  if (!value) return '';\n  let result = '';\n  for (let i = 0; i < value.length; i++) {\n    const ch = value.charCodeAt(i);\n    // Allow a-z A-Z 0-9\n    if (\n      (ch >= 0x30 && ch <= 0x39) || // 0-9\n      (ch >= 0x41 && ch <= 0x5a) || // A-Z\n      (ch >= 0x61 && ch <= 0x7a)    // a-z\n    ) {\n      result += value[i];\n    } else {\n      // CSS hex escape: backslash + hex code + trailing space (CSS spec requirement)\n      result += `\\\\${ch.toString(16).toUpperCase()} `;\n    }\n  }\n  return result;\n}\n","/**\n * @module @arcis/node/sanitizers/graphql\n * GraphQL injection prevention (sdk-vectors.md tier 1 #21).\n *\n * Two threats covered:\n *\n * 1. **Depth-bomb DoS** — nested-query payloads like\n *    `query { x { x { x { ... } } } }` to ridiculous depth that explode\n *    resolver work (each `{` typically maps to a database round-trip).\n *    Even a 50-deep query against a real schema can hammer the\n *    backend; 1000-deep crashes the resolver entirely.\n *\n * 2. **Introspection abuse** — `__schema` / `__type` / `__typename`\n *    queries that let an attacker enumerate the entire schema, then\n *    use that map to find sensitive fields, deprecated mutations,\n *    or unprotected admin paths. Production GraphQL endpoints should\n *    disable introspection by default.\n *\n * v1 is regex-based: count `{` / `}` for nesting depth (no escape\n * handling — strings inside the query that contain `{` will\n * over-count). False positives are an acceptable tradeoff for v1\n * because (a) the depth threshold is well above legitimate query\n * shapes, (b) a real GraphQL parser pulls in `graphql` as a runtime\n * dep — significant for a sanitizer that ships in every Arcis\n * install. Customers running queries near the threshold can either\n * raise `maxDepth` or bring their own AST pre-pass.\n *\n * NOT included in v1:\n * - Field-count limit (some servers have this; orthogonal to depth)\n * - Alias-bomb detection (`q { f1: foo, f2: foo, ...}` — easier as\n *   a length-check than a parse)\n * - Variable rebinding attacks\n *\n * Each is a follow-up if customers ask. Documented inline.\n */\n\nexport interface GraphqlGuardOptions {\n  /** Maximum allowed nesting depth. Default: 10. Most legit queries are <8. */\n  maxDepth?: number;\n  /** Maximum query string length in characters. Default: 10000. */\n  maxLength?: number;\n  /**\n   * Block introspection queries (`__schema`, `__type`). Default: true.\n   * Set `false` in development if you rely on GraphiQL / Apollo\n   * Studio. Production should leave this on.\n   */\n  blockIntrospection?: boolean;\n  /**\n   * Maximum number of field aliases per query (`label: field`).\n   * Default: 50. Alias-bomb attacks repeat the same expensive field\n   * under many labels to multiply backend cost. Real queries rarely\n   * use more than 20 aliases. improvements.md §1.2 V34.\n   */\n  maxAliases?: number;\n  /**\n   * Reject queries whose fragment definitions form a cycle (direct\n   * self-reference `fragment A on T { ...A }` or indirect\n   * `A → B → A`). Such cycles either infinite-loop a naive resolver\n   * or get rejected by `graphql-core` with a 500. Default: true.\n   * improvements.md §1.2 V34.\n   */\n  blockFragmentCycles?: boolean;\n}\n\nexport type GraphqlViolation =\n  | 'depth'\n  | 'length'\n  | 'introspection'\n  | 'aliases'\n  | 'fragment_cycle';\n\nexport interface GraphqlGuardResult {\n  /** True if the query violated any configured limit. */\n  blocked: boolean;\n  /** Which limit fired first. Precedence: depth → introspection → aliases → fragment_cycle → length. */\n  reason?: GraphqlViolation;\n  /** Observed nesting depth. Always returned. */\n  depth: number;\n  /** Observed length. Always returned. */\n  length: number;\n  /** Observed alias count (improvements.md §1.2 V34). Always returned. */\n  aliases: number;\n}\n\nconst DEFAULTS = {\n  maxDepth: 10,\n  maxLength: 10000,\n  blockIntrospection: true,\n  maxAliases: 50,\n  blockFragmentCycles: true,\n} as const;\n\n/**\n * Word-boundary `__` reflection markers. GraphQL spec reserves the\n * `__` prefix for introspection — `__schema`, `__type`, `__typename`,\n * `__typeKind`, `__directive`. Matching the prefix catches them all\n * without enumerating; the boundary anchor (`\\b__`) avoids\n * false-matches on user fields like `last__updated_at`.\n *\n * `__typename` is the one introspection field that's commonly used\n * legitimately (Apollo client requests it on every query). We\n * deliberately let it through by listing the others explicitly.\n */\nconst INTROSPECTION_PATTERN = /\\b__(schema|type|typeKind|directive)\\b/;\n\n/**\n * Compute the maximum nesting depth of a GraphQL query string by\n * counting `{` and `}` runs. Strings inside the query (e.g.\n * `field(arg: \"{...}\")`) inflate this — accepted v1 tradeoff. A\n * future AST-mode implementation lives behind a separate flag.\n */\nfunction computeDepth(query: string): number {\n  let depth = 0;\n  let max = 0;\n  for (let i = 0; i < query.length; i++) {\n    const c = query.charCodeAt(i);\n    if (c === 123 /* { */) {\n      depth++;\n      if (depth > max) max = depth;\n    } else if (c === 125 /* } */) {\n      // Don't go negative on malformed input — clamp at 0.\n      if (depth > 0) depth--;\n    }\n  }\n  return max;\n}\n\n// `label: field` — alias of one field to another name. Excludes\n// patterns like `query Foo:` where Foo is an operation name (handled\n// because the regex requires the second token to be a name AND\n// alias semantics only apply inside `{...}` blocks; this is a\n// lexical approximation, not a parser).\nconst ALIAS_PATTERN = /\\b([a-zA-Z_][a-zA-Z0-9_]*)\\s*:\\s*([a-zA-Z_][a-zA-Z0-9_]*)\\b/g;\n\n// `fragment <name> on <type> {` — captures the fragment NAME.\nconst FRAGMENT_DEF_PATTERN =\n  /\\bfragment\\s+([a-zA-Z_][a-zA-Z0-9_]*)\\s+on\\s+[a-zA-Z_][a-zA-Z0-9_]*\\s*\\{/g;\n\n// `...FragmentName` spread inside a selection set.\nconst FRAGMENT_SPREAD_PATTERN = /\\.\\.\\.\\s*([a-zA-Z_][a-zA-Z0-9_]*)\\b/g;\n\nfunction countAliases(query: string): number {\n  let n = 0;\n  ALIAS_PATTERN.lastIndex = 0;\n  while (ALIAS_PATTERN.exec(query) !== null) n++;\n  return n;\n}\n\n/**\n * Detect cycles in the fragment spread graph (improvements.md §1.2 V34).\n *\n * Walks `fragment X on T { ... }` definitions, builds adjacency from\n * each fragment to the names it spreads, and runs DFS for a back-edge.\n * Body of each fragment is brace-matched so the subsequent query\n * operation's spreads don't pollute the graph.\n */\nfunction hasFragmentCycle(query: string): boolean {\n  const deps = new Map<string, Set<string>>();\n  FRAGMENT_DEF_PATTERN.lastIndex = 0;\n  let match: RegExpExecArray | null;\n  while ((match = FRAGMENT_DEF_PATTERN.exec(query)) !== null) {\n    const name = match[1];\n    const bodyStart = match.index + match[0].length; // right after `{`\n    // Brace-match to find the body end.\n    let depth = 1;\n    let i = bodyStart;\n    while (i < query.length && depth > 0) {\n      const ch = query[i];\n      if (ch === '{') depth++;\n      else if (ch === '}') depth--;\n      i++;\n    }\n    const bodyEnd = depth === 0 ? i - 1 : i;\n    const body = query.slice(bodyStart, bodyEnd);\n    const spreads = new Set<string>();\n    FRAGMENT_SPREAD_PATTERN.lastIndex = 0;\n    let sm: RegExpExecArray | null;\n    while ((sm = FRAGMENT_SPREAD_PATTERN.exec(body)) !== null) {\n      spreads.add(sm[1]);\n    }\n    deps.set(name, spreads);\n  }\n  if (deps.size === 0) return false;\n\n  const WHITE = 0;\n  const GRAY = 1;\n  const BLACK = 2;\n  const color = new Map<string, number>();\n  for (const name of deps.keys()) color.set(name, WHITE);\n\n  function visit(name: string): boolean {\n    if (color.get(name) === GRAY) return true; // back-edge\n    if (color.get(name) === BLACK) return false;\n    if (!deps.has(name)) return false; // spread to undefined fragment\n    color.set(name, GRAY);\n    for (const child of deps.get(name)!) {\n      if (visit(child)) return true;\n    }\n    color.set(name, BLACK);\n    return false;\n  }\n\n  for (const name of deps.keys()) {\n    if (visit(name)) return true;\n  }\n  return false;\n}\n\n/**\n * Inspect a GraphQL query against the configured limits. Returns a\n * structured result; the middleware below uses this directly. Pure\n * function — no I/O, no res handle.\n */\nexport function inspectGraphqlQuery(\n  query: string,\n  options: GraphqlGuardOptions = {},\n): GraphqlGuardResult {\n  const maxDepth = options.maxDepth ?? DEFAULTS.maxDepth;\n  const maxLength = options.maxLength ?? DEFAULTS.maxLength;\n  const blockIntrospection = options.blockIntrospection ?? DEFAULTS.blockIntrospection;\n  const maxAliases = options.maxAliases ?? DEFAULTS.maxAliases;\n  const blockFragmentCycles =\n    options.blockFragmentCycles ?? DEFAULTS.blockFragmentCycles;\n\n  const length = query.length;\n  const depth = computeDepth(query);\n  const aliases = countAliases(query);\n\n  // Precedence: depth → introspection → aliases → fragment_cycle →\n  // length. Cheapest-to-explain failures first; length last because\n  // it's the easiest false-positive (long queries with deep inline\n  // fragments are legitimate). improvements.md §1.2 V34.\n  if (depth > maxDepth) {\n    return { blocked: true, reason: 'depth', depth, length, aliases };\n  }\n  if (blockIntrospection && INTROSPECTION_PATTERN.test(query)) {\n    return { blocked: true, reason: 'introspection', depth, length, aliases };\n  }\n  if (aliases > maxAliases) {\n    return { blocked: true, reason: 'aliases', depth, length, aliases };\n  }\n  if (blockFragmentCycles && hasFragmentCycle(query)) {\n    return { blocked: true, reason: 'fragment_cycle', depth, length, aliases };\n  }\n  if (length > maxLength) {\n    return { blocked: true, reason: 'length', depth, length, aliases };\n  }\n\n  return { blocked: false, depth, length, aliases };\n}\n\n/**\n * Detect-only API matching the rest of the sanitizer module surface\n * (`detectXss` / `detectSql` / `detectXxe` / etc.). Returns a boolean\n * for callers that just want a yes/no — use `inspectGraphqlQuery` if\n * you need the structured reason.\n */\nexport function detectGraphqlAbuse(\n  query: string,\n  options?: GraphqlGuardOptions,\n): boolean {\n  if (typeof query !== 'string' || query.length === 0) return false;\n  return inspectGraphqlQuery(query, options).blocked;\n}\n"]}