@arcis/node 1.4.0 → 1.4.3
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.
- package/README.md +1 -1
- package/dist/core/constants.d.ts +2 -2
- package/dist/core/constants.d.ts.map +1 -1
- package/dist/core/index.js +11 -3
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +11 -3
- package/dist/core/index.mjs.map +1 -1
- package/dist/core/types.d.ts +6 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +527 -63
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +525 -65
- package/dist/index.mjs.map +1 -1
- package/dist/logging/index.js.map +1 -1
- package/dist/logging/index.mjs.map +1 -1
- package/dist/middleware/bot-detection.d.ts.map +1 -1
- package/dist/middleware/cookies.d.ts.map +1 -1
- package/dist/middleware/csrf.d.ts +10 -0
- package/dist/middleware/csrf.d.ts.map +1 -1
- package/dist/middleware/hpp.d.ts.map +1 -1
- package/dist/middleware/index.d.ts +2 -0
- package/dist/middleware/index.d.ts.map +1 -1
- package/dist/middleware/index.js +671 -39
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/index.mjs +671 -41
- package/dist/middleware/index.mjs.map +1 -1
- package/dist/middleware/main.d.ts.map +1 -1
- package/dist/middleware/rate-limit.d.ts.map +1 -1
- package/dist/middleware/signup-protection.d.ts +65 -0
- package/dist/middleware/signup-protection.d.ts.map +1 -0
- package/dist/middleware/telemetry.d.ts +36 -0
- package/dist/middleware/telemetry.d.ts.map +1 -0
- package/dist/sanitizers/encode.d.ts.map +1 -1
- package/dist/sanitizers/index.d.ts +1 -0
- package/dist/sanitizers/index.d.ts.map +1 -1
- package/dist/sanitizers/index.js +113 -37
- package/dist/sanitizers/index.js.map +1 -1
- package/dist/sanitizers/index.mjs +111 -38
- package/dist/sanitizers/index.mjs.map +1 -1
- package/dist/sanitizers/ldap.d.ts +42 -0
- package/dist/sanitizers/ldap.d.ts.map +1 -0
- package/dist/sanitizers/path.d.ts.map +1 -1
- package/dist/sanitizers/pii.d.ts.map +1 -1
- package/dist/sanitizers/sanitize.d.ts.map +1 -1
- package/dist/sanitizers/ssti.d.ts.map +1 -1
- package/dist/sanitizers/xxe.d.ts.map +1 -1
- package/dist/stores/index.js +21 -1
- package/dist/stores/index.js.map +1 -1
- package/dist/stores/index.mjs +21 -1
- package/dist/stores/index.mjs.map +1 -1
- package/dist/stores/memory.d.ts +4 -10
- package/dist/stores/memory.d.ts.map +1 -1
- package/dist/telemetry/client.d.ts +60 -0
- package/dist/telemetry/client.d.ts.map +1 -0
- package/dist/telemetry/index.d.ts +3 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/types.d.ts +59 -0
- package/dist/telemetry/types.d.ts.map +1 -0
- package/dist/validation/index.js +41 -21
- package/dist/validation/index.js.map +1 -1
- package/dist/validation/index.mjs +41 -21
- package/dist/validation/index.mjs.map +1 -1
- package/package.json +8 -2
|
@@ -25,13 +25,24 @@ 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) */
|
|
32
40
|
/<script[^>]*>[\s\S]*?<\/script>/gi,
|
|
33
41
|
/** Standalone/unclosed script tags */
|
|
34
42
|
/<script[^>]*>/gi,
|
|
43
|
+
/** style — CSS expression() and behavior: attacks (IE-era but still relevant) */
|
|
44
|
+
/<style[^>]*>[\s\S]*?<\/style>/gi,
|
|
45
|
+
/<style[^>]*/gi,
|
|
35
46
|
/** iframe — full block and partial/unclosed */
|
|
36
47
|
/<iframe[^>]*>[\s\S]*?<\/iframe>/gi,
|
|
37
48
|
/<iframe[^>]*/gi,
|
|
@@ -52,7 +63,15 @@ var XSS_REMOVE_PATTERNS = [
|
|
|
52
63
|
/javascript\s*:/gi,
|
|
53
64
|
/vbscript\s*:/gi,
|
|
54
65
|
/** data: URIs with HTML/script content */
|
|
55
|
-
/data\s*:\s*text\/html[^>\s]*/gi
|
|
66
|
+
/data\s*:\s*text\/html[^>\s]*/gi,
|
|
67
|
+
/** form tag injection — phishing via action= redirection */
|
|
68
|
+
/<form[\s>][^>]*/gi,
|
|
69
|
+
/** meta tag injection — http-equiv refresh or CSP bypass */
|
|
70
|
+
/<meta[\s>][^>]*/gi,
|
|
71
|
+
/** base href hijacking */
|
|
72
|
+
/<base[\s>][^>]*/gi,
|
|
73
|
+
/** link tag injection — stylesheet or preload attacks */
|
|
74
|
+
/<link[\s>][^>]*/gi
|
|
56
75
|
];
|
|
57
76
|
var SQL_PATTERNS = [
|
|
58
77
|
/** SQL keywords */
|
|
@@ -116,8 +135,8 @@ var COMMAND_PATTERNS = [
|
|
|
116
135
|
/[;&|`]/g,
|
|
117
136
|
/** Command substitution: $( ... ) — matched as a pair to reduce false positives */
|
|
118
137
|
/\$\(/g,
|
|
119
|
-
/** URL-encoded
|
|
120
|
-
/%0[
|
|
138
|
+
/** URL-encoded control characters (%00-%0F): null, tab, vtab, formfeed, LF, CR */
|
|
139
|
+
/%0[0-9a-f]/gi
|
|
121
140
|
];
|
|
122
141
|
var DANGEROUS_PROTO_KEYS = /* @__PURE__ */ new Set([
|
|
123
142
|
"__proto__",
|
|
@@ -321,26 +340,31 @@ function sanitizePath(input, collectThreats = false) {
|
|
|
321
340
|
const threats = [];
|
|
322
341
|
let value = input;
|
|
323
342
|
let wasSanitized = false;
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
343
|
+
value = value.normalize("NFKC");
|
|
344
|
+
let prev;
|
|
345
|
+
do {
|
|
346
|
+
prev = value;
|
|
347
|
+
for (const pattern of PATH_PATTERNS) {
|
|
327
348
|
pattern.lastIndex = 0;
|
|
328
|
-
if (
|
|
329
|
-
|
|
330
|
-
if (
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
349
|
+
if (pattern.test(value)) {
|
|
350
|
+
pattern.lastIndex = 0;
|
|
351
|
+
if (collectThreats) {
|
|
352
|
+
const matches = value.match(pattern);
|
|
353
|
+
if (matches) {
|
|
354
|
+
for (const match of matches) {
|
|
355
|
+
threats.push({
|
|
356
|
+
type: "path_traversal",
|
|
357
|
+
pattern: pattern.source,
|
|
358
|
+
original: match
|
|
359
|
+
});
|
|
360
|
+
}
|
|
337
361
|
}
|
|
338
362
|
}
|
|
363
|
+
value = value.replace(pattern, "");
|
|
364
|
+
wasSanitized = true;
|
|
339
365
|
}
|
|
340
|
-
value = value.replace(pattern, "");
|
|
341
|
-
wasSanitized = true;
|
|
342
366
|
}
|
|
343
|
-
}
|
|
367
|
+
} while (value !== prev);
|
|
344
368
|
if (collectThreats) {
|
|
345
369
|
return { value, wasSanitized, threats };
|
|
346
370
|
}
|
|
@@ -348,9 +372,10 @@ function sanitizePath(input, collectThreats = false) {
|
|
|
348
372
|
}
|
|
349
373
|
function detectPathTraversal(input) {
|
|
350
374
|
if (typeof input !== "string") return false;
|
|
375
|
+
const normalized = input.normalize("NFKC");
|
|
351
376
|
for (const pattern of PATH_PATTERNS) {
|
|
352
377
|
pattern.lastIndex = 0;
|
|
353
|
-
if (pattern.test(
|
|
378
|
+
if (pattern.test(normalized)) {
|
|
354
379
|
return true;
|
|
355
380
|
}
|
|
356
381
|
}
|
|
@@ -408,7 +433,7 @@ function sanitizeString(value, options = {}) {
|
|
|
408
433
|
if (value.length > maxSize) {
|
|
409
434
|
throw new InputTooLargeError(maxSize, value.length);
|
|
410
435
|
}
|
|
411
|
-
const reject = options.mode
|
|
436
|
+
const reject = options.mode === "reject";
|
|
412
437
|
let result = value;
|
|
413
438
|
if (options.sql !== false) {
|
|
414
439
|
if (reject) {
|
|
@@ -563,10 +588,24 @@ var SSTI_DETECT_PATTERNS = [
|
|
|
563
588
|
/\{\{\s*(?:self|request|lipsum|cycler|joiner|namespace|range)\b/gi
|
|
564
589
|
];
|
|
565
590
|
var SSTI_REMOVE_PATTERNS = [
|
|
591
|
+
/** Jinja2 / Twig: {{ ... }} — always strip (not valid in any JS context) */
|
|
566
592
|
/\{\{.*?\}\}/g,
|
|
567
|
-
|
|
593
|
+
/**
|
|
594
|
+
* Freemarker / Spring EL: ${...} — strip when expression contains operators,
|
|
595
|
+
* method calls, or Python dunder patterns (sandbox escape).
|
|
596
|
+
* Bare ${name} and ${user.name} are left intact (JS template literal syntax).
|
|
597
|
+
*/
|
|
598
|
+
/\$\{[^}]*__\w+__[^}]*\}/g,
|
|
599
|
+
/\$\{[^}]*[?!()*+\-/][^}]*\}/g,
|
|
600
|
+
/** ERB / EJS: <%= ... %> */
|
|
568
601
|
/<%[=\-]?.*?%>/gs,
|
|
569
|
-
|
|
602
|
+
/**
|
|
603
|
+
* Pug / Jade: #{...} — same narrowing as ${ above, plus dunder detection.
|
|
604
|
+
* #{name} output expressions are left intact.
|
|
605
|
+
*/
|
|
606
|
+
/#\{[^}]*__\w+__[^}]*\}/g,
|
|
607
|
+
/#\{[^}]*[?!()*+\-/][^}]*\}/g,
|
|
608
|
+
/** Python dunder sandbox escape — always strip */
|
|
570
609
|
/__(?:class|mro|subclasses|globals|builtins|import)__/gi
|
|
571
610
|
];
|
|
572
611
|
function sanitizeSsti(input, collectThreats = false) {
|
|
@@ -613,6 +652,8 @@ function detectSsti(input) {
|
|
|
613
652
|
}
|
|
614
653
|
|
|
615
654
|
// src/sanitizers/xxe.ts
|
|
655
|
+
var MAX_XXE_INPUT_BYTES = 1e6;
|
|
656
|
+
var MAX_ENTITY_REFERENCES = 64;
|
|
616
657
|
var XXE_DETECT_PATTERNS = [
|
|
617
658
|
/** DOCTYPE declaration */
|
|
618
659
|
/<!DOCTYPE\b/gi,
|
|
@@ -642,6 +683,19 @@ function sanitizeXxe(input, collectThreats = false) {
|
|
|
642
683
|
const threats = [];
|
|
643
684
|
let value = input;
|
|
644
685
|
let wasSanitized = false;
|
|
686
|
+
if (value.length > MAX_XXE_INPUT_BYTES) {
|
|
687
|
+
if (collectThreats) {
|
|
688
|
+
threats.push({ type: "xxe", pattern: "oversize_input", original: `length=${value.length}` });
|
|
689
|
+
}
|
|
690
|
+
return collectThreats ? { value: "", wasSanitized: true, threats } : "";
|
|
691
|
+
}
|
|
692
|
+
const entityRefs = value.match(/&\w+;/g);
|
|
693
|
+
if (entityRefs && entityRefs.length > MAX_ENTITY_REFERENCES) {
|
|
694
|
+
if (collectThreats) {
|
|
695
|
+
threats.push({ type: "xxe", pattern: "entity_expansion", original: `count=${entityRefs.length}` });
|
|
696
|
+
}
|
|
697
|
+
return collectThreats ? { value: "", wasSanitized: true, threats } : "";
|
|
698
|
+
}
|
|
645
699
|
for (const pattern of XXE_REMOVE_PATTERNS) {
|
|
646
700
|
pattern.lastIndex = 0;
|
|
647
701
|
if (pattern.test(value)) {
|
|
@@ -679,12 +733,10 @@ function detectXxe(input) {
|
|
|
679
733
|
}
|
|
680
734
|
|
|
681
735
|
// src/sanitizers/jsonp.ts
|
|
682
|
-
var SAFE_CALLBACK_PATTERN = /^[a-zA-Z_$][a-zA-Z0-9_$.
|
|
736
|
+
var SAFE_CALLBACK_PATTERN = /^[a-zA-Z_$][a-zA-Z0-9_$.]*$/;
|
|
683
737
|
var DANGEROUS_CALLBACK_PATTERNS = [
|
|
684
|
-
|
|
738
|
+
/\.\./
|
|
685
739
|
// prototype chain traversal
|
|
686
|
-
/\[\s*\]/
|
|
687
|
-
// empty bracket access
|
|
688
740
|
];
|
|
689
741
|
function sanitizeJsonpCallback(callback, maxLength = 128) {
|
|
690
742
|
if (typeof callback !== "string" || callback.length === 0) {
|
|
@@ -769,7 +821,7 @@ function detectHeaderInjection(input) {
|
|
|
769
821
|
|
|
770
822
|
// src/sanitizers/pii.ts
|
|
771
823
|
var 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;
|
|
772
|
-
var PHONE_RE = /(?:\+?1[-.\s]?)?\(?[2-9]\d{2}\)?[-.\s]?\d{3}[-.\s]?\d{4}/g;
|
|
824
|
+
var PHONE_RE = /(?<!\d)(?:\+?1[-.\s]?)?\(?[2-9]\d{2}\)?[-.\s]?\d{3}[-.\s]?\d{4}(?!\d)/g;
|
|
773
825
|
var CREDIT_CARD_RE = /\b(?:\d[ -]*?){13,19}\b/g;
|
|
774
826
|
var SSN_RE = /\b\d{3}[-\s]\d{2}[-\s]\d{4}\b/g;
|
|
775
827
|
var 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;
|
|
@@ -930,16 +982,18 @@ function encodeForAttribute(value) {
|
|
|
930
982
|
function encodeForJs(value) {
|
|
931
983
|
if (!value) return "";
|
|
932
984
|
let result = "";
|
|
933
|
-
for (
|
|
934
|
-
const
|
|
935
|
-
if (
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
result +=
|
|
939
|
-
} else if (
|
|
940
|
-
result += `\\x${
|
|
985
|
+
for (const char of value) {
|
|
986
|
+
const cp = char.codePointAt(0);
|
|
987
|
+
if (cp >= 48 && cp <= 57 || // 0-9
|
|
988
|
+
cp >= 65 && cp <= 90 || // A-Z
|
|
989
|
+
cp >= 97 && cp <= 122) {
|
|
990
|
+
result += char;
|
|
991
|
+
} else if (cp < 256) {
|
|
992
|
+
result += `\\x${cp.toString(16).toUpperCase().padStart(2, "0")}`;
|
|
993
|
+
} else if (cp <= 65535) {
|
|
994
|
+
result += `\\u${cp.toString(16).toUpperCase().padStart(4, "0")}`;
|
|
941
995
|
} else {
|
|
942
|
-
result += `\\u${
|
|
996
|
+
result += `\\u{${cp.toString(16).toUpperCase()}}`;
|
|
943
997
|
}
|
|
944
998
|
}
|
|
945
999
|
return result;
|
|
@@ -966,6 +1020,25 @@ function encodeForCss(value) {
|
|
|
966
1020
|
return result;
|
|
967
1021
|
}
|
|
968
1022
|
|
|
969
|
-
|
|
1023
|
+
// src/sanitizers/ldap.ts
|
|
1024
|
+
var LDAP_FILTER_CHARS = /[*()\\\x00]/g;
|
|
1025
|
+
var LDAP_DN_CHARS = /[,+<>;"=\/\\\x00*()\x00]/g;
|
|
1026
|
+
var LDAP_DETECT_PATTERN = /[*()\\\x00]/;
|
|
1027
|
+
var LDAP_INJECTION_PATTERN = /\)\s*\(|\*\s*\)\s*\(/;
|
|
1028
|
+
var escapeChar = (char) => "\\" + char.charCodeAt(0).toString(16).padStart(2, "0");
|
|
1029
|
+
function sanitizeLdapFilter(input) {
|
|
1030
|
+
if (typeof input !== "string") return String(input);
|
|
1031
|
+
return input.replace(LDAP_FILTER_CHARS, escapeChar);
|
|
1032
|
+
}
|
|
1033
|
+
function sanitizeLdapDn(input) {
|
|
1034
|
+
if (typeof input !== "string") return String(input);
|
|
1035
|
+
return input.replace(LDAP_DN_CHARS, escapeChar);
|
|
1036
|
+
}
|
|
1037
|
+
function detectLdapInjection(input) {
|
|
1038
|
+
if (typeof input !== "string") return false;
|
|
1039
|
+
return LDAP_DETECT_PATTERN.test(input) || LDAP_INJECTION_PATTERN.test(input);
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
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
1043
|
//# sourceMappingURL=index.mjs.map
|
|
971
1044
|
//# sourceMappingURL=index.mjs.map
|