@arcis/node 1.4.0 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +1 -1
  2. package/dist/core/constants.d.ts +2 -2
  3. package/dist/core/constants.d.ts.map +1 -1
  4. package/dist/core/index.js +11 -3
  5. package/dist/core/index.js.map +1 -1
  6. package/dist/core/index.mjs +11 -3
  7. package/dist/core/index.mjs.map +1 -1
  8. package/dist/index.js +125 -46
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +126 -47
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/logging/index.js.map +1 -1
  13. package/dist/logging/index.mjs.map +1 -1
  14. package/dist/middleware/csrf.d.ts.map +1 -1
  15. package/dist/middleware/index.js +62 -30
  16. package/dist/middleware/index.js.map +1 -1
  17. package/dist/middleware/index.mjs +63 -31
  18. package/dist/middleware/index.mjs.map +1 -1
  19. package/dist/middleware/rate-limit.d.ts.map +1 -1
  20. package/dist/sanitizers/encode.d.ts.map +1 -1
  21. package/dist/sanitizers/index.d.ts +1 -0
  22. package/dist/sanitizers/index.d.ts.map +1 -1
  23. package/dist/sanitizers/index.js +90 -32
  24. package/dist/sanitizers/index.js.map +1 -1
  25. package/dist/sanitizers/index.mjs +88 -33
  26. package/dist/sanitizers/index.mjs.map +1 -1
  27. package/dist/sanitizers/ldap.d.ts +42 -0
  28. package/dist/sanitizers/ldap.d.ts.map +1 -0
  29. package/dist/sanitizers/path.d.ts.map +1 -1
  30. package/dist/sanitizers/sanitize.d.ts.map +1 -1
  31. package/dist/sanitizers/ssti.d.ts.map +1 -1
  32. package/dist/stores/index.js +21 -1
  33. package/dist/stores/index.js.map +1 -1
  34. package/dist/stores/index.mjs +21 -1
  35. package/dist/stores/index.mjs.map +1 -1
  36. package/dist/stores/memory.d.ts +4 -10
  37. package/dist/stores/memory.d.ts.map +1 -1
  38. package/dist/validation/index.js +38 -21
  39. package/dist/validation/index.js.map +1 -1
  40. package/dist/validation/index.mjs +38 -21
  41. package/dist/validation/index.mjs.map +1 -1
  42. package/package.json +2 -2
@@ -25,7 +25,15 @@ var XSS_PATTERNS = [
25
25
  /** URL-encoded script tags */
26
26
  /%3Cscript/gi,
27
27
  /** SVG with onload */
28
- /<svg[^>]*onload/gi
28
+ /<svg[^>]*onload/gi,
29
+ /** form tags — phishing/credential harvesting via action= redirection */
30
+ /<form[\s>]/gi,
31
+ /** meta tags — http-equiv refresh redirects or CSP bypass */
32
+ /<meta[\s>]/gi,
33
+ /** base href hijacking — redirects all relative URLs to attacker domain */
34
+ /<base[\s>]/gi,
35
+ /** link tag injection — stylesheet or preload CSRF attacks */
36
+ /<link[\s>]/gi
29
37
  ];
30
38
  var XSS_REMOVE_PATTERNS = [
31
39
  /** Full script blocks (content + tags) */
@@ -52,7 +60,15 @@ var XSS_REMOVE_PATTERNS = [
52
60
  /javascript\s*:/gi,
53
61
  /vbscript\s*:/gi,
54
62
  /** data: URIs with HTML/script content */
55
- /data\s*:\s*text\/html[^>\s]*/gi
63
+ /data\s*:\s*text\/html[^>\s]*/gi,
64
+ /** form tag injection — phishing via action= redirection */
65
+ /<form[\s>][^>]*/gi,
66
+ /** meta tag injection — http-equiv refresh or CSP bypass */
67
+ /<meta[\s>][^>]*/gi,
68
+ /** base href hijacking */
69
+ /<base[\s>][^>]*/gi,
70
+ /** link tag injection — stylesheet or preload attacks */
71
+ /<link[\s>][^>]*/gi
56
72
  ];
57
73
  var SQL_PATTERNS = [
58
74
  /** SQL keywords */
@@ -116,8 +132,8 @@ var COMMAND_PATTERNS = [
116
132
  /[;&|`]/g,
117
133
  /** Command substitution: $( ... ) — matched as a pair to reduce false positives */
118
134
  /\$\(/g,
119
- /** URL-encoded newline/carriage-return injection (%0a, %0d) */
120
- /%0[ad]/gi
135
+ /** URL-encoded control characters (%00-%0F): null, tab, vtab, formfeed, LF, CR */
136
+ /%0[0-9a-f]/gi
121
137
  ];
122
138
  var DANGEROUS_PROTO_KEYS = /* @__PURE__ */ new Set([
123
139
  "__proto__",
@@ -321,26 +337,31 @@ function sanitizePath(input, collectThreats = false) {
321
337
  const threats = [];
322
338
  let value = input;
323
339
  let wasSanitized = false;
324
- for (const pattern of PATH_PATTERNS) {
325
- pattern.lastIndex = 0;
326
- if (pattern.test(value)) {
340
+ value = value.normalize("NFKC");
341
+ let prev;
342
+ do {
343
+ prev = value;
344
+ for (const pattern of PATH_PATTERNS) {
327
345
  pattern.lastIndex = 0;
328
- if (collectThreats) {
329
- const matches = value.match(pattern);
330
- if (matches) {
331
- for (const match of matches) {
332
- threats.push({
333
- type: "path_traversal",
334
- pattern: pattern.source,
335
- original: match
336
- });
346
+ if (pattern.test(value)) {
347
+ pattern.lastIndex = 0;
348
+ if (collectThreats) {
349
+ const matches = value.match(pattern);
350
+ if (matches) {
351
+ for (const match of matches) {
352
+ threats.push({
353
+ type: "path_traversal",
354
+ pattern: pattern.source,
355
+ original: match
356
+ });
357
+ }
337
358
  }
338
359
  }
360
+ value = value.replace(pattern, "");
361
+ wasSanitized = true;
339
362
  }
340
- value = value.replace(pattern, "");
341
- wasSanitized = true;
342
363
  }
343
- }
364
+ } while (value !== prev);
344
365
  if (collectThreats) {
345
366
  return { value, wasSanitized, threats };
346
367
  }
@@ -348,9 +369,10 @@ function sanitizePath(input, collectThreats = false) {
348
369
  }
349
370
  function detectPathTraversal(input) {
350
371
  if (typeof input !== "string") return false;
372
+ const normalized = input.normalize("NFKC");
351
373
  for (const pattern of PATH_PATTERNS) {
352
374
  pattern.lastIndex = 0;
353
- if (pattern.test(input)) {
375
+ if (pattern.test(normalized)) {
354
376
  return true;
355
377
  }
356
378
  }
@@ -408,7 +430,7 @@ function sanitizeString(value, options = {}) {
408
430
  if (value.length > maxSize) {
409
431
  throw new InputTooLargeError(maxSize, value.length);
410
432
  }
411
- const reject = options.mode !== "sanitize";
433
+ const reject = options.mode === "reject";
412
434
  let result = value;
413
435
  if (options.sql !== false) {
414
436
  if (reject) {
@@ -563,10 +585,22 @@ var SSTI_DETECT_PATTERNS = [
563
585
  /\{\{\s*(?:self|request|lipsum|cycler|joiner|namespace|range)\b/gi
564
586
  ];
565
587
  var SSTI_REMOVE_PATTERNS = [
588
+ /** Jinja2 / Twig: {{ ... }} — always strip (not valid in any JS context) */
566
589
  /\{\{.*?\}\}/g,
567
- /\$\{.*?\}/g,
590
+ /**
591
+ * Freemarker / Spring EL: ${...} — only strip when the expression contains
592
+ * operators (?!*+-/), method calls (), or known-dangerous prefixes.
593
+ * Bare ${name} and ${user.name} are left intact (JS template literal syntax).
594
+ */
595
+ /\$\{[^}]*[?!()*+\-/][^}]*\}/g,
596
+ /** ERB / EJS: <%= ... %> */
568
597
  /<%[=\-]?.*?%>/gs,
569
- /#\{.*?\}/g,
598
+ /**
599
+ * Pug / Jade: #{...} — same narrowing as ${ above.
600
+ * #{name} output expressions are left intact.
601
+ */
602
+ /#\{[^}]*[?!()*+\-/][^}]*\}/g,
603
+ /** Python dunder sandbox escape — always strip */
570
604
  /__(?:class|mro|subclasses|globals|builtins|import)__/gi
571
605
  ];
572
606
  function sanitizeSsti(input, collectThreats = false) {
@@ -930,16 +964,18 @@ function encodeForAttribute(value) {
930
964
  function encodeForJs(value) {
931
965
  if (!value) return "";
932
966
  let result = "";
933
- for (let i = 0; i < value.length; i++) {
934
- const ch = value.charCodeAt(i);
935
- if (ch >= 48 && ch <= 57 || // 0-9
936
- ch >= 65 && ch <= 90 || // A-Z
937
- ch >= 97 && ch <= 122) {
938
- result += value[i];
939
- } else if (ch < 256) {
940
- result += `\\x${ch.toString(16).toUpperCase().padStart(2, "0")}`;
967
+ for (const char of value) {
968
+ const cp = char.codePointAt(0);
969
+ if (cp >= 48 && cp <= 57 || // 0-9
970
+ cp >= 65 && cp <= 90 || // A-Z
971
+ cp >= 97 && cp <= 122) {
972
+ result += char;
973
+ } else if (cp < 256) {
974
+ result += `\\x${cp.toString(16).toUpperCase().padStart(2, "0")}`;
975
+ } else if (cp <= 65535) {
976
+ result += `\\u${cp.toString(16).toUpperCase().padStart(4, "0")}`;
941
977
  } else {
942
- result += `\\u${ch.toString(16).toUpperCase().padStart(4, "0")}`;
978
+ result += `\\u{${cp.toString(16).toUpperCase()}}`;
943
979
  }
944
980
  }
945
981
  return result;
@@ -966,6 +1002,25 @@ function encodeForCss(value) {
966
1002
  return result;
967
1003
  }
968
1004
 
969
- export { createSanitizer, detectCommandInjection, detectHeaderInjection, detectJsonpInjection, detectNoSqlInjection, detectPathTraversal, detectPii, detectPrototypePollution, detectSql, detectSsti, detectXss, detectXxe, encodeForAttribute, encodeForCss, encodeForHtml, encodeForJs, encodeForUrl, encodeHtmlEntities, getDangerousOperators, getDangerousProtoKeys, isDangerousNoSqlKey, isDangerousProtoKey, isPlainObject, redactObjectPii, redactPii, sanitizeCommand, sanitizeHeaderValue, sanitizeHeaders, sanitizeJsonpCallback, sanitizeObject, sanitizePath, sanitizeSql, sanitizeSsti, sanitizeString, sanitizeXss, sanitizeXxe, scanObjectPii, scanPii };
1005
+ // src/sanitizers/ldap.ts
1006
+ var LDAP_FILTER_CHARS = /[*()\\\x00]/g;
1007
+ var LDAP_DN_CHARS = /[,+<>;"=\/\\\x00*()\x00]/g;
1008
+ var LDAP_DETECT_PATTERN = /[*()\\\x00]/;
1009
+ var LDAP_INJECTION_PATTERN = /\)\s*\(|\*\s*\)\s*\(/;
1010
+ var escapeChar = (char) => "\\" + char.charCodeAt(0).toString(16).padStart(2, "0");
1011
+ function sanitizeLdapFilter(input) {
1012
+ if (typeof input !== "string") return String(input);
1013
+ return input.replace(LDAP_FILTER_CHARS, escapeChar);
1014
+ }
1015
+ function sanitizeLdapDn(input) {
1016
+ if (typeof input !== "string") return String(input);
1017
+ return input.replace(LDAP_DN_CHARS, escapeChar);
1018
+ }
1019
+ function detectLdapInjection(input) {
1020
+ if (typeof input !== "string") return false;
1021
+ return LDAP_DETECT_PATTERN.test(input) || LDAP_INJECTION_PATTERN.test(input);
1022
+ }
1023
+
1024
+ export { createSanitizer, detectCommandInjection, detectHeaderInjection, detectJsonpInjection, detectLdapInjection, detectNoSqlInjection, detectPathTraversal, detectPii, detectPrototypePollution, detectSql, detectSsti, detectXss, detectXxe, encodeForAttribute, encodeForCss, encodeForHtml, encodeForJs, encodeForUrl, encodeHtmlEntities, getDangerousOperators, getDangerousProtoKeys, isDangerousNoSqlKey, isDangerousProtoKey, isPlainObject, redactObjectPii, redactPii, sanitizeCommand, sanitizeHeaderValue, sanitizeHeaders, sanitizeJsonpCallback, sanitizeLdapDn, sanitizeLdapFilter, sanitizeObject, sanitizePath, sanitizeSql, sanitizeSsti, sanitizeString, sanitizeXss, sanitizeXxe, scanObjectPii, scanPii };
970
1025
  //# sourceMappingURL=index.mjs.map
971
1026
  //# sourceMappingURL=index.mjs.map