@arcis/node 1.6.1 → 1.6.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.
Files changed (75) hide show
  1. package/README.md +5 -3
  2. package/dist/_third_party/rate-limit/abstract.d.ts +36 -0
  3. package/dist/_third_party/rate-limit/abstract.d.ts.map +1 -0
  4. package/dist/_third_party/rate-limit/bursty.d.ts +21 -0
  5. package/dist/_third_party/rate-limit/bursty.d.ts.map +1 -0
  6. package/dist/_third_party/rate-limit/index.d.ts +12 -0
  7. package/dist/_third_party/rate-limit/index.d.ts.map +1 -0
  8. package/dist/_third_party/rate-limit/memory-storage.d.ts +28 -0
  9. package/dist/_third_party/rate-limit/memory-storage.d.ts.map +1 -0
  10. package/dist/_third_party/rate-limit/memory.d.ts +23 -0
  11. package/dist/_third_party/rate-limit/memory.d.ts.map +1 -0
  12. package/dist/_third_party/rate-limit/record.d.ts +11 -0
  13. package/dist/_third_party/rate-limit/record.d.ts.map +1 -0
  14. package/dist/_third_party/rate-limit/types.d.ts +39 -0
  15. package/dist/_third_party/rate-limit/types.d.ts.map +1 -0
  16. package/dist/astro/index.js +405 -0
  17. package/dist/astro/index.js.map +1 -1
  18. package/dist/astro/index.mjs +405 -0
  19. package/dist/astro/index.mjs.map +1 -1
  20. package/dist/bun/index.js +405 -0
  21. package/dist/bun/index.js.map +1 -1
  22. package/dist/bun/index.mjs +405 -0
  23. package/dist/bun/index.mjs.map +1 -1
  24. package/dist/fastify/index.js +405 -0
  25. package/dist/fastify/index.js.map +1 -1
  26. package/dist/fastify/index.mjs +405 -0
  27. package/dist/fastify/index.mjs.map +1 -1
  28. package/dist/hono/index.js +405 -0
  29. package/dist/hono/index.js.map +1 -1
  30. package/dist/hono/index.mjs +405 -0
  31. package/dist/hono/index.mjs.map +1 -1
  32. package/dist/index.d.ts +2 -0
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +754 -5
  35. package/dist/index.js.map +1 -1
  36. package/dist/index.mjs +754 -6
  37. package/dist/index.mjs.map +1 -1
  38. package/dist/koa/index.js +405 -0
  39. package/dist/koa/index.js.map +1 -1
  40. package/dist/koa/index.mjs +405 -0
  41. package/dist/koa/index.mjs.map +1 -1
  42. package/dist/middleware/brute-force.d.ts +69 -0
  43. package/dist/middleware/brute-force.d.ts.map +1 -0
  44. package/dist/middleware/index.js +702 -1
  45. package/dist/middleware/index.js.map +1 -1
  46. package/dist/middleware/index.mjs +702 -1
  47. package/dist/middleware/index.mjs.map +1 -1
  48. package/dist/middleware/nestjs.d.ts +50 -1
  49. package/dist/middleware/nestjs.d.ts.map +1 -1
  50. package/dist/middleware/protect.d.ts +9 -0
  51. package/dist/middleware/protect.d.ts.map +1 -1
  52. package/dist/nestjs/index.js +57 -2
  53. package/dist/nestjs/index.js.map +1 -1
  54. package/dist/nestjs/index.mjs +57 -3
  55. package/dist/nestjs/index.mjs.map +1 -1
  56. package/dist/nextjs/index.js +405 -0
  57. package/dist/nextjs/index.js.map +1 -1
  58. package/dist/nextjs/index.mjs +405 -0
  59. package/dist/nextjs/index.mjs.map +1 -1
  60. package/dist/nuxt/index.js +405 -0
  61. package/dist/nuxt/index.js.map +1 -1
  62. package/dist/nuxt/index.mjs +405 -0
  63. package/dist/nuxt/index.mjs.map +1 -1
  64. package/dist/sanitizers/index.js +2 -1
  65. package/dist/sanitizers/index.js.map +1 -1
  66. package/dist/sanitizers/index.mjs +2 -1
  67. package/dist/sanitizers/index.mjs.map +1 -1
  68. package/dist/sanitizers/ldap.d.ts.map +1 -1
  69. package/dist/sanitizers/prompt-injection.d.ts +3 -3
  70. package/dist/sanitizers/prompt-injection.d.ts.map +1 -1
  71. package/dist/sveltekit/index.js +405 -0
  72. package/dist/sveltekit/index.js.map +1 -1
  73. package/dist/sveltekit/index.mjs +405 -0
  74. package/dist/sveltekit/index.mjs.map +1 -1
  75. package/package.json +2 -2
package/dist/index.mjs CHANGED
@@ -1078,9 +1078,10 @@ function detectXxe(input) {
1078
1078
  // src/sanitizers/ldap.ts
1079
1079
  var LDAP_DETECT_PATTERN = /[*()\\\x00]/;
1080
1080
  var LDAP_INJECTION_PATTERN = /\)\s*\(|\*\s*\)\s*\(/;
1081
+ var LDAP_NOT_BYPASS_PATTERN = /\)\s*\(\s*!|&\s*\(\s*!|\|\s*\(\s*!/;
1081
1082
  function detectLdapInjection(input) {
1082
1083
  if (typeof input !== "string") return false;
1083
- return LDAP_DETECT_PATTERN.test(input) || LDAP_INJECTION_PATTERN.test(input);
1084
+ return LDAP_DETECT_PATTERN.test(input) || LDAP_INJECTION_PATTERN.test(input) || LDAP_NOT_BYPASS_PATTERN.test(input);
1084
1085
  }
1085
1086
 
1086
1087
  // src/sanitizers/xpath.ts
@@ -9271,6 +9272,411 @@ var bot_patterns_default = [
9271
9272
  "ZuperlistBot\\/"
9272
9273
  ],
9273
9274
  forbidden: []
9275
+ },
9276
+ {
9277
+ id: "ext-ahrefsbotsiteaudit",
9278
+ name: "ahrefsbotsiteaudit",
9279
+ category: "SEO",
9280
+ patterns: [
9281
+ "Ahrefs(Bot|SiteAudit)"
9282
+ ],
9283
+ forbidden: []
9284
+ },
9285
+ {
9286
+ id: "ext-amazonproductdiscovery",
9287
+ name: "amazonproductdiscovery",
9288
+ category: "SEARCH_ENGINE",
9289
+ patterns: [
9290
+ "AmazonProductDiscovery"
9291
+ ],
9292
+ forbidden: []
9293
+ },
9294
+ {
9295
+ id: "ext-amazonsellerinitiatedlisting",
9296
+ name: "amazonsellerinitiatedlisting",
9297
+ category: "SEARCH_ENGINE",
9298
+ patterns: [
9299
+ "AmazonSellerInitiatedListing"
9300
+ ],
9301
+ forbidden: []
9302
+ },
9303
+ {
9304
+ id: "ext-cclaudebbot",
9305
+ name: "cclaudebbot",
9306
+ category: "GENERIC",
9307
+ patterns: [
9308
+ "[cC]laude[bB]ot"
9309
+ ],
9310
+ forbidden: []
9311
+ },
9312
+ {
9313
+ id: "ext-meta-externalagent",
9314
+ name: "meta-externalagent",
9315
+ category: "GENERIC",
9316
+ patterns: [
9317
+ "meta-externalagent\\/"
9318
+ ],
9319
+ forbidden: []
9320
+ },
9321
+ {
9322
+ id: "ext-meta-externalfetcher",
9323
+ name: "meta-externalfetcher",
9324
+ category: "GENERIC",
9325
+ patterns: [
9326
+ "meta-externalfetcher\\/"
9327
+ ],
9328
+ forbidden: []
9329
+ },
9330
+ {
9331
+ id: "ext-hydrozenio",
9332
+ name: "hydrozenio",
9333
+ category: "MONITORING",
9334
+ patterns: [
9335
+ "Hydrozen\\.io"
9336
+ ],
9337
+ forbidden: []
9338
+ },
9339
+ {
9340
+ id: "ext-yextbot",
9341
+ name: "yextbot",
9342
+ category: "SEO",
9343
+ patterns: [
9344
+ "YextBot\\/"
9345
+ ],
9346
+ forbidden: []
9347
+ },
9348
+ {
9349
+ id: "ext-datadogsynthetics",
9350
+ name: "datadogsynthetics",
9351
+ category: "MONITORING",
9352
+ patterns: [
9353
+ "DatadogSynthetics"
9354
+ ],
9355
+ forbidden: []
9356
+ },
9357
+ {
9358
+ id: "ext-observepoint",
9359
+ name: "observepoint",
9360
+ category: "MONITORING",
9361
+ patterns: [
9362
+ "ObservePoint"
9363
+ ],
9364
+ forbidden: []
9365
+ },
9366
+ {
9367
+ id: "ext-checkly",
9368
+ name: "checkly",
9369
+ category: "MONITORING",
9370
+ patterns: [
9371
+ "Checkly"
9372
+ ],
9373
+ forbidden: []
9374
+ },
9375
+ {
9376
+ id: "ext-alittleclient",
9377
+ name: "alittleclient",
9378
+ category: "GENERIC",
9379
+ patterns: [
9380
+ "ALittle Client"
9381
+ ],
9382
+ forbidden: []
9383
+ },
9384
+ {
9385
+ id: "ext-aliyunsecbot",
9386
+ name: "aliyunsecbot",
9387
+ category: "GENERIC",
9388
+ patterns: [
9389
+ "AliyunSecBot"
9390
+ ],
9391
+ forbidden: []
9392
+ },
9393
+ {
9394
+ id: "ext-claude-web",
9395
+ name: "claude-web",
9396
+ category: "GENERIC",
9397
+ patterns: [
9398
+ "Claude-Web"
9399
+ ],
9400
+ forbidden: []
9401
+ },
9402
+ {
9403
+ id: "ext-google-extended",
9404
+ name: "google-extended",
9405
+ category: "GENERIC",
9406
+ patterns: [
9407
+ "Google-Extended"
9408
+ ],
9409
+ forbidden: []
9410
+ },
9411
+ {
9412
+ id: "ext-serankingbacklinksbot",
9413
+ name: "serankingbacklinksbot",
9414
+ category: "SEO",
9415
+ patterns: [
9416
+ "SERankingBacklinksBot"
9417
+ ],
9418
+ forbidden: []
9419
+ },
9420
+ {
9421
+ id: "ext-cmschecker",
9422
+ name: "cmschecker",
9423
+ category: "SEO",
9424
+ patterns: [
9425
+ "CMSChecker"
9426
+ ],
9427
+ forbidden: []
9428
+ },
9429
+ {
9430
+ id: "ext-wayback",
9431
+ name: "wayback",
9432
+ category: "GENERIC",
9433
+ patterns: [
9434
+ "Wayback"
9435
+ ],
9436
+ forbidden: []
9437
+ },
9438
+ {
9439
+ id: "ext-playwright",
9440
+ name: "playwright",
9441
+ category: "GENERIC",
9442
+ patterns: [
9443
+ "Playwright"
9444
+ ],
9445
+ forbidden: []
9446
+ },
9447
+ {
9448
+ id: "ext-puppeteer",
9449
+ name: "puppeteer",
9450
+ category: "GENERIC",
9451
+ patterns: [
9452
+ "Puppeteer"
9453
+ ],
9454
+ forbidden: []
9455
+ },
9456
+ {
9457
+ id: "ext-selenium",
9458
+ name: "selenium",
9459
+ category: "GENERIC",
9460
+ patterns: [
9461
+ "Selenium"
9462
+ ],
9463
+ forbidden: []
9464
+ },
9465
+ {
9466
+ id: "ext-nikto",
9467
+ name: "nikto",
9468
+ category: "GENERIC",
9469
+ patterns: [
9470
+ "Nikto"
9471
+ ],
9472
+ forbidden: []
9473
+ },
9474
+ {
9475
+ id: "ext-sqlmap",
9476
+ name: "sqlmap",
9477
+ category: "GENERIC",
9478
+ patterns: [
9479
+ "sqlmap"
9480
+ ],
9481
+ forbidden: []
9482
+ },
9483
+ {
9484
+ id: "ext-zmeu",
9485
+ name: "zmeu",
9486
+ category: "GENERIC",
9487
+ patterns: [
9488
+ "ZmEu"
9489
+ ],
9490
+ forbidden: []
9491
+ },
9492
+ {
9493
+ id: "ext-masscan",
9494
+ name: "masscan",
9495
+ category: "GENERIC",
9496
+ patterns: [
9497
+ "masscan"
9498
+ ],
9499
+ forbidden: []
9500
+ },
9501
+ {
9502
+ id: "ext-wpscan",
9503
+ name: "wpscan",
9504
+ category: "GENERIC",
9505
+ patterns: [
9506
+ "WPScan"
9507
+ ],
9508
+ forbidden: []
9509
+ },
9510
+ {
9511
+ id: "ext-aacunetix",
9512
+ name: "aacunetix",
9513
+ category: "GENERIC",
9514
+ patterns: [
9515
+ "[aA]cunetix"
9516
+ ],
9517
+ forbidden: []
9518
+ },
9519
+ {
9520
+ id: "ext-nessus",
9521
+ name: "nessus",
9522
+ category: "GENERIC",
9523
+ patterns: [
9524
+ "Nessus"
9525
+ ],
9526
+ forbidden: []
9527
+ },
9528
+ {
9529
+ id: "ext-ddirbbuster",
9530
+ name: "ddirbbuster",
9531
+ category: "GENERIC",
9532
+ patterns: [
9533
+ "[dD]ir[Bb]uster"
9534
+ ],
9535
+ forbidden: []
9536
+ },
9537
+ {
9538
+ id: "ext-colly",
9539
+ name: "colly",
9540
+ category: "GENERIC",
9541
+ patterns: [
9542
+ "colly"
9543
+ ],
9544
+ forbidden: []
9545
+ },
9546
+ {
9547
+ id: "ext-mmechanize",
9548
+ name: "mmechanize",
9549
+ category: "GENERIC",
9550
+ patterns: [
9551
+ "[mM]echanize"
9552
+ ],
9553
+ forbidden: []
9554
+ },
9555
+ {
9556
+ id: "ext-airaiscanning",
9557
+ name: "airaiscanning",
9558
+ category: "GENERIC",
9559
+ patterns: [
9560
+ "air\\.ai\\/scanning"
9561
+ ],
9562
+ forbidden: []
9563
+ },
9564
+ {
9565
+ id: "ext-asnriskscorer",
9566
+ name: "asnriskscorer",
9567
+ category: "GENERIC",
9568
+ patterns: [
9569
+ "asnriskscorer"
9570
+ ],
9571
+ forbidden: []
9572
+ },
9573
+ {
9574
+ id: "ext-oicrawler",
9575
+ name: "oicrawler",
9576
+ category: "SEARCH_ENGINE",
9577
+ patterns: [
9578
+ "OICrawler"
9579
+ ],
9580
+ forbidden: []
9581
+ },
9582
+ {
9583
+ id: "ext-l9scan",
9584
+ name: "l9scan",
9585
+ category: "GENERIC",
9586
+ patterns: [
9587
+ "l9scan"
9588
+ ],
9589
+ forbidden: []
9590
+ },
9591
+ {
9592
+ id: "ext-slaccalebot",
9593
+ name: "slaccalebot",
9594
+ category: "SEO",
9595
+ patterns: [
9596
+ "SlaccaleBot"
9597
+ ],
9598
+ forbidden: []
9599
+ },
9600
+ {
9601
+ id: "ext-customasynchttpclient",
9602
+ name: "customasynchttpclient",
9603
+ category: "GENERIC",
9604
+ patterns: [
9605
+ "CustomAsyncHttpClient"
9606
+ ],
9607
+ forbidden: []
9608
+ },
9609
+ {
9610
+ id: "ext-gemini-deep-research",
9611
+ name: "gemini-deep-research",
9612
+ category: "SEARCH_ENGINE",
9613
+ patterns: [
9614
+ "Gemini-Deep-Research"
9615
+ ],
9616
+ forbidden: []
9617
+ },
9618
+ {
9619
+ id: "ext-perplexity-user",
9620
+ name: "perplexity-user",
9621
+ category: "SEARCH_ENGINE",
9622
+ patterns: [
9623
+ "Perplexity-User"
9624
+ ],
9625
+ forbidden: []
9626
+ },
9627
+ {
9628
+ id: "ext-perplexityuser",
9629
+ name: "perplexityuser",
9630
+ category: "SEARCH_ENGINE",
9631
+ patterns: [
9632
+ "PerplexityUser"
9633
+ ],
9634
+ forbidden: []
9635
+ },
9636
+ {
9637
+ id: "ext-meta-webindexer",
9638
+ name: "meta-webindexer",
9639
+ category: "GENERIC",
9640
+ patterns: [
9641
+ "meta-webindexer"
9642
+ ],
9643
+ forbidden: []
9644
+ },
9645
+ {
9646
+ id: "ext-duckassistbot",
9647
+ name: "duckassistbot",
9648
+ category: "SEARCH_ENGINE",
9649
+ patterns: [
9650
+ "DuckAssistBot"
9651
+ ],
9652
+ forbidden: []
9653
+ },
9654
+ {
9655
+ id: "ext-mistralai-user",
9656
+ name: "mistralai-user",
9657
+ category: "GENERIC",
9658
+ patterns: [
9659
+ "MistralAI-User"
9660
+ ],
9661
+ forbidden: []
9662
+ },
9663
+ {
9664
+ id: "ext-webzio",
9665
+ name: "webzio",
9666
+ category: "SEO",
9667
+ patterns: [
9668
+ "webzio"
9669
+ ],
9670
+ forbidden: []
9671
+ },
9672
+ {
9673
+ id: "ext-newsai",
9674
+ name: "newsai",
9675
+ category: "GENERIC",
9676
+ patterns: [
9677
+ "newsai\\/"
9678
+ ],
9679
+ forbidden: []
9274
9680
  }
9275
9681
  ];
9276
9682
 
@@ -10065,6 +10471,297 @@ function signupProtection(options = {}) {
10065
10471
  return middleware;
10066
10472
  }
10067
10473
 
10474
+ // src/_third_party/rate-limit/abstract.ts
10475
+ var AbstractLimiter = class {
10476
+ constructor(opts) {
10477
+ if (!Number.isFinite(opts.points)) {
10478
+ throw new Error("points must be a finite number");
10479
+ }
10480
+ if (!Number.isFinite(opts.duration) || opts.duration < 0) {
10481
+ throw new Error("duration must be a finite, non-negative number");
10482
+ }
10483
+ this._points = opts.points;
10484
+ this._duration = opts.duration;
10485
+ this._blockDuration = typeof opts.blockDuration === "undefined" ? 0 : opts.blockDuration;
10486
+ this._execEvenly = Boolean(opts.execEvenly);
10487
+ this._execEvenlyMinDelayMs = typeof opts.execEvenlyMinDelayMs === "undefined" ? Math.ceil(this._duration * 1e3 / Math.max(this._points, 1)) : opts.execEvenlyMinDelayMs;
10488
+ if (typeof opts.keyPrefix === "undefined") {
10489
+ this._keyPrefix = "arcis";
10490
+ } else if (typeof opts.keyPrefix !== "string") {
10491
+ throw new Error("keyPrefix must be a string");
10492
+ } else {
10493
+ this._keyPrefix = opts.keyPrefix;
10494
+ }
10495
+ }
10496
+ get points() {
10497
+ return this._points;
10498
+ }
10499
+ get duration() {
10500
+ return this._duration;
10501
+ }
10502
+ get msDuration() {
10503
+ return this._duration * 1e3;
10504
+ }
10505
+ get blockDuration() {
10506
+ return this._blockDuration;
10507
+ }
10508
+ get msBlockDuration() {
10509
+ return this._blockDuration * 1e3;
10510
+ }
10511
+ get execEvenly() {
10512
+ return this._execEvenly;
10513
+ }
10514
+ get execEvenlyMinDelayMs() {
10515
+ return this._execEvenlyMinDelayMs;
10516
+ }
10517
+ get keyPrefix() {
10518
+ return this._keyPrefix;
10519
+ }
10520
+ _getKeySecDuration(options = {}) {
10521
+ return typeof options.customDuration === "number" && options.customDuration >= 0 ? options.customDuration : this._duration;
10522
+ }
10523
+ _getKey(key) {
10524
+ return this._keyPrefix.length > 0 ? `${this._keyPrefix}:${key}` : key;
10525
+ }
10526
+ };
10527
+
10528
+ // src/_third_party/rate-limit/types.ts
10529
+ var LimiterResult = class {
10530
+ constructor(remainingPoints = 0, msBeforeNext = 0, consumedPoints = 0, isFirstInDuration = false) {
10531
+ this.remainingPoints = remainingPoints;
10532
+ this.msBeforeNext = msBeforeNext;
10533
+ this.consumedPoints = consumedPoints;
10534
+ this.isFirstInDuration = isFirstInDuration;
10535
+ }
10536
+ };
10537
+
10538
+ // src/_third_party/rate-limit/record.ts
10539
+ var StorageRecord = class {
10540
+ constructor(value, expiresAt, timeoutId = null) {
10541
+ this.value = Math.trunc(value);
10542
+ this.expiresAt = expiresAt;
10543
+ this.timeoutId = timeoutId;
10544
+ }
10545
+ };
10546
+
10547
+ // src/_third_party/rate-limit/memory-storage.ts
10548
+ var MemoryStorage = class {
10549
+ constructor() {
10550
+ this._storage = /* @__PURE__ */ new Map();
10551
+ }
10552
+ /**
10553
+ * Increment the counter for `key` by `value`. If the key has no record
10554
+ * (or its TTL has expired), a new record is created with `durationSec`
10555
+ * lifetime.
10556
+ */
10557
+ incrby(key, value, durationSec) {
10558
+ const record = this._storage.get(key);
10559
+ if (record) {
10560
+ const msBeforeExpires = record.expiresAt ? record.expiresAt - Date.now() : -1;
10561
+ if (!record.expiresAt || msBeforeExpires > 0) {
10562
+ record.value = record.value + value;
10563
+ return new LimiterResult(0, msBeforeExpires, record.value, false);
10564
+ }
10565
+ return this.set(key, value, durationSec);
10566
+ }
10567
+ return this.set(key, value, durationSec);
10568
+ }
10569
+ /**
10570
+ * Write the counter for `key` to `value`, replacing any existing
10571
+ * record. `durationSec` of 0 means "never expires".
10572
+ */
10573
+ set(key, value, durationSec) {
10574
+ const durationMs = durationSec * 1e3;
10575
+ const existing = this._storage.get(key);
10576
+ if (existing && existing.timeoutId) {
10577
+ clearTimeout(existing.timeoutId);
10578
+ }
10579
+ const record = new StorageRecord(value, durationMs > 0 ? Date.now() + durationMs : null);
10580
+ this._storage.set(key, record);
10581
+ if (durationMs > 0) {
10582
+ record.timeoutId = setTimeout(() => {
10583
+ this._storage.delete(key);
10584
+ }, durationMs);
10585
+ if (typeof record.timeoutId.unref === "function") {
10586
+ record.timeoutId.unref();
10587
+ }
10588
+ }
10589
+ return new LimiterResult(0, durationMs === 0 ? -1 : durationMs, record.value, true);
10590
+ }
10591
+ get(key) {
10592
+ const record = this._storage.get(key);
10593
+ if (!record) return null;
10594
+ const msBeforeExpires = record.expiresAt ? record.expiresAt - Date.now() : -1;
10595
+ return new LimiterResult(0, msBeforeExpires, record.value, false);
10596
+ }
10597
+ delete(key) {
10598
+ const record = this._storage.get(key);
10599
+ if (!record) return false;
10600
+ if (record.timeoutId) {
10601
+ clearTimeout(record.timeoutId);
10602
+ }
10603
+ this._storage.delete(key);
10604
+ return true;
10605
+ }
10606
+ /** Inspect the underlying map. Test-only and not part of the public API. */
10607
+ _dump() {
10608
+ return this._storage.entries();
10609
+ }
10610
+ /** Clear all records. Used by tests and by `Limiter.dispose()`. */
10611
+ clear() {
10612
+ for (const record of this._storage.values()) {
10613
+ if (record.timeoutId) clearTimeout(record.timeoutId);
10614
+ }
10615
+ this._storage.clear();
10616
+ }
10617
+ };
10618
+
10619
+ // src/_third_party/rate-limit/memory.ts
10620
+ var MemoryLimiter = class extends AbstractLimiter {
10621
+ constructor(opts) {
10622
+ super(opts);
10623
+ this._storage = new MemoryStorage();
10624
+ }
10625
+ consume(key, pointsToConsume = 1, options = {}) {
10626
+ return new Promise((resolve2, reject) => {
10627
+ const rlKey = this._getKey(key);
10628
+ const secDuration = this._getKeySecDuration(options);
10629
+ let res = this._storage.incrby(rlKey, pointsToConsume, secDuration);
10630
+ res.remainingPoints = Math.max(this._points - res.consumedPoints, 0);
10631
+ if (res.consumedPoints > this._points) {
10632
+ if (this._blockDuration > 0 && res.consumedPoints <= this._points + pointsToConsume) {
10633
+ res = this._storage.set(rlKey, res.consumedPoints, this._blockDuration);
10634
+ }
10635
+ reject(res);
10636
+ return;
10637
+ }
10638
+ if (this._execEvenly && res.msBeforeNext > 0 && !res.isFirstInDuration) {
10639
+ let delay = Math.ceil(res.msBeforeNext / (res.remainingPoints + 2));
10640
+ if (delay < this._execEvenlyMinDelayMs) {
10641
+ delay = res.consumedPoints * this._execEvenlyMinDelayMs;
10642
+ }
10643
+ res.msBeforeNext = Math.max(res.msBeforeNext - delay, 0);
10644
+ setTimeout(resolve2, delay, res);
10645
+ return;
10646
+ }
10647
+ resolve2(res);
10648
+ });
10649
+ }
10650
+ penalty(key, points = 1, options = {}) {
10651
+ const rlKey = this._getKey(key);
10652
+ const secDuration = this._getKeySecDuration(options);
10653
+ const res = this._storage.incrby(rlKey, points, secDuration);
10654
+ res.remainingPoints = Math.max(this._points - res.consumedPoints, 0);
10655
+ return Promise.resolve(res);
10656
+ }
10657
+ reward(key, points = 1, options = {}) {
10658
+ const rlKey = this._getKey(key);
10659
+ const secDuration = this._getKeySecDuration(options);
10660
+ const res = this._storage.incrby(rlKey, -points, secDuration);
10661
+ res.remainingPoints = Math.max(this._points - res.consumedPoints, 0);
10662
+ return Promise.resolve(res);
10663
+ }
10664
+ block(key, secDuration) {
10665
+ const msDuration = secDuration * 1e3;
10666
+ const initPoints = this._points + 1;
10667
+ this._storage.set(this._getKey(key), initPoints, secDuration);
10668
+ return Promise.resolve(new LimiterResult(0, msDuration === 0 ? -1 : msDuration, initPoints, false));
10669
+ }
10670
+ get(key) {
10671
+ const res = this._storage.get(this._getKey(key));
10672
+ if (res !== null) {
10673
+ res.remainingPoints = Math.max(this._points - res.consumedPoints, 0);
10674
+ }
10675
+ return Promise.resolve(res);
10676
+ }
10677
+ delete(key) {
10678
+ return Promise.resolve(this._storage.delete(this._getKey(key)));
10679
+ }
10680
+ /** Test/teardown helper. Drops every key and clears timers. */
10681
+ dispose() {
10682
+ this._storage.clear();
10683
+ }
10684
+ };
10685
+
10686
+ // src/middleware/brute-force.ts
10687
+ function defaultKeyGenerator2(req) {
10688
+ const xff = req.headers["x-forwarded-for"];
10689
+ if (typeof xff === "string" && xff.length > 0) {
10690
+ const first = xff.split(",")[0]?.trim();
10691
+ if (first) return first;
10692
+ }
10693
+ if (typeof req.ip === "string" && req.ip.length > 0) return req.ip;
10694
+ const remote = req.socket?.remoteAddress;
10695
+ return typeof remote === "string" && remote.length > 0 ? remote : "unknown";
10696
+ }
10697
+ function bruteForceProtection(options = {}) {
10698
+ const fastPoints = options.fastPoints ?? 5;
10699
+ const fastDuration = options.fastDuration ?? 60;
10700
+ const slowPoints = options.slowPoints ?? 20;
10701
+ const slowDuration = options.slowDuration ?? 900;
10702
+ const blockDuration = options.blockDuration ?? 900;
10703
+ const keyGenerator = options.keyGenerator ?? defaultKeyGenerator2;
10704
+ const statusCode = options.statusCode ?? 429;
10705
+ const message = options.message ?? "Too many login attempts. Please try again later.";
10706
+ const skip = options.skip;
10707
+ const fast = new MemoryLimiter({
10708
+ points: fastPoints,
10709
+ duration: fastDuration,
10710
+ keyPrefix: "arcis:bf:fast"
10711
+ });
10712
+ const slow = new MemoryLimiter({
10713
+ points: slowPoints,
10714
+ duration: slowDuration,
10715
+ blockDuration,
10716
+ keyPrefix: "arcis:bf:slow"
10717
+ });
10718
+ const controller = {
10719
+ reward: (key, points = 1) => slow.reward(key, points),
10720
+ delete: async (key) => {
10721
+ const a = await fast.delete(key);
10722
+ const b = await slow.delete(key);
10723
+ return a || b;
10724
+ },
10725
+ get: (key) => slow.get(key),
10726
+ block: (key, secDuration) => slow.block(key, secDuration)
10727
+ };
10728
+ const handler = async (req, res, next) => {
10729
+ try {
10730
+ if (skip?.(req)) return next();
10731
+ const key = keyGenerator(req);
10732
+ req.arcisBruteForce = controller;
10733
+ const slowRes = await slow.consume(key, 1);
10734
+ const fastRes = await fast.consume(key, 1);
10735
+ res.setHeader("X-RateLimit-Limit", String(slowPoints));
10736
+ res.setHeader(
10737
+ "X-RateLimit-Remaining",
10738
+ String(Math.min(fastRes.remainingPoints, slowRes.remainingPoints))
10739
+ );
10740
+ res.setHeader(
10741
+ "X-RateLimit-Reset",
10742
+ String(Math.ceil(Math.max(slowRes.msBeforeNext, fastRes.msBeforeNext) / 1e3))
10743
+ );
10744
+ next();
10745
+ } catch (rejection) {
10746
+ if (rejection instanceof LimiterResult || isLimiterResultShape(rejection)) {
10747
+ const retryAfter = Math.ceil(rejection.msBeforeNext / 1e3);
10748
+ res.setHeader("X-RateLimit-Limit", String(slowPoints));
10749
+ res.setHeader("X-RateLimit-Remaining", "0");
10750
+ res.setHeader("X-RateLimit-Reset", String(retryAfter));
10751
+ res.setHeader("Retry-After", String(retryAfter));
10752
+ res.status(statusCode).json({ error: message, retryAfter });
10753
+ return;
10754
+ }
10755
+ console.error("[arcis] brute-force middleware error:", rejection);
10756
+ next();
10757
+ }
10758
+ };
10759
+ return Object.assign(handler, { controller });
10760
+ }
10761
+ function isLimiterResultShape(x) {
10762
+ return typeof x === "object" && x !== null && typeof x.consumedPoints === "number" && typeof x.msBeforeNext === "number";
10763
+ }
10764
+
10068
10765
  // src/middleware/protect.ts
10069
10766
  function getClientIp(req) {
10070
10767
  const xff = req?.headers?.["x-forwarded-for"] ?? req?.headers?.["X-Forwarded-For"];
@@ -10115,6 +10812,10 @@ function protectLogin(options = {}) {
10115
10812
  const middlewares = [];
10116
10813
  const rl = resolve(options.rateLimit, { max: 5, windowMs: 6e4 });
10117
10814
  if (rl) middlewares.push(createRateLimiter(rl));
10815
+ if (options.bruteForce) {
10816
+ const bfOpts = options.bruteForce === true ? {} : options.bruteForce;
10817
+ middlewares.push(bruteForceProtection(bfOpts));
10818
+ }
10118
10819
  const bot = resolve(options.bot, {
10119
10820
  deny: ["AUTOMATED"],
10120
10821
  statusCode: 403,
@@ -10398,13 +11099,25 @@ var SIGNATURES = [
10398
11099
  rule: "ignore-previous-instructions",
10399
11100
  // Two clauses:
10400
11101
  // 1. ignore|disregard|... + adjectives? + a target object word (like
10401
- // "instructions", "rules") catches "ignore your safety rules".
11102
+ // "instructions", "rules"). Catches "ignore your safety rules".
10402
11103
  // 2. ignore|disregard|... + (the|all|any) + (previous|above|prior|...)
10403
- // with no trailing noun catches "disregard the above".
10404
- pattern: /\b(?:ignore|disregard|forget|override|bypass)\s+(?:(?:all|your|the|any|previous|prior|above|original|initial|system|safety)\s+)*(?:instructions?|rules?|directions?|guidelines?|prompts?|policies|directives|commands?|restrictions?|filters?|safety|content)\b|\b(?:ignore|disregard|forget|override|bypass)\s+(?:all\s+|the\s+|any\s+)?(?:previous|prior|above|preceding|earlier|original|initial)\b/i,
11104
+ // with no trailing noun. Catches "disregard the above".
11105
+ // Verb set widened in v1.7 to include skip/neglect/overlook/omit (the
11106
+ // combinatorial jailbreak corpus uses these interchangeably with
11107
+ // ignore/disregard/forget).
11108
+ pattern: /\b(?:ignore|disregard|forget|override|bypass|skip|neglect|overlook|omit)\s+(?:(?:all|your|the|any|previous|prior|above|original|initial|system|safety|preceding|earlier|foregoing)\s+)*(?:instructions?|rules?|directions?|guidelines?|prompts?|policies|directives?|commands?|restrictions?|filters?|safety|content|context|conversation|directive|messages?|communication|requests?|inputs?)\b|\b(?:ignore|disregard|forget|override|bypass|skip|neglect|overlook|omit)\s+(?:all\s+|the\s+|any\s+)?(?:previous|prior|above|preceding|earlier|original|initial|foregoing)\b/i,
10405
11109
  severity: "high",
10406
11110
  description: "Direct instruction override attempt"
10407
11111
  },
11112
+ {
11113
+ rule: "instruction-bypass-phrases",
11114
+ // Multi-word verbs that don't fit the single-token alternation in
11115
+ // `ignore-previous-instructions`. Catches "pay no attention to your
11116
+ // previous instructions", "do not follow the above rules", etc.
11117
+ pattern: /\b(?:pay\s+no\s+attention\s+to|do\s+not\s+(?:follow|obey|adhere\s+to|comply\s+with))\s+(?:(?:all|your|the|any|previous|prior|above|original|initial|system|safety|preceding|earlier|foregoing)\s+)*(?:instructions?|rules?|directions?|guidelines?|prompts?|policies|directives?|commands?|restrictions?|filters?|safety|content|context|directive|messages?)\b/i,
11118
+ severity: "high",
11119
+ description: "Multi-word instruction-bypass phrase (pay no attention to / do not follow)"
11120
+ },
10408
11121
  {
10409
11122
  rule: "jailbreak-dan",
10410
11123
  pattern: /\b(?:DAN|STAN|DUDE|DAVE|JEDI|EvilBot|AIM|BetterDAN|AntiGPT|AntiClaude)\b(?:[\s.,!?]|mode|prompt|jailbreak|persona)/i,
@@ -10528,7 +11241,7 @@ var SIGNATURES = [
10528
11241
  // a tool, or to trick the model into echoing a synthesized
10529
11242
  // tool_call that the runtime then executes.
10530
11243
  //
10531
- // Narrow patterns match the literal JSON keys and inline
11244
+ // Narrow patterns. Match the literal JSON keys and inline
10532
11245
  // tool-name shapes. Won't false-positive on plain English text
10533
11246
  // discussing tools.
10534
11247
  {
@@ -10561,6 +11274,41 @@ var SIGNATURES = [
10561
11274
  severity: "high",
10562
11275
  description: "Claude/OpenAI tool-use XML-style tag forgery"
10563
11276
  },
11277
+ // ── Prompt-template marker forgeries ────────────────────────────────
11278
+ // Catches inline forgery of the special tokens that LLM runtimes use
11279
+ // to delimit roles. If a user can land any of these in their input
11280
+ // and the host concatenates the input into a prompt without
11281
+ // re-tokenizing, the model treats the suffix as a new system turn.
11282
+ //
11283
+ // Covered runtimes:
11284
+ // - ChatML (OpenAI / Llama 3 chat): <|im_start|>, <|im_end|>
11285
+ // - Llama 2 chat: [INST] <<SYS>> ... <</SYS>>
11286
+ // - guidance/handlebars: {{#system~}}, {{/system~}}, {{#assistant~}}
11287
+ // - Markdown link spoof: [system](#assistant), [admin](#context)
11288
+ {
11289
+ rule: "chatml-template-marker",
11290
+ pattern: /<\|im_(?:start|end)\|>(?:\s*(?:system|assistant|user|tool|function))?/i,
11291
+ severity: "high",
11292
+ description: "ChatML special token forgery (<|im_start|>...) to spoof a role turn"
11293
+ },
11294
+ {
11295
+ rule: "llama2-system-marker",
11296
+ pattern: /<<\s*\/?\s*SYS\s*>>|\[\s*\/?\s*INST\s*\]/i,
11297
+ severity: "high",
11298
+ description: "Llama 2 [INST]/<<SYS>> instruction-template marker forgery"
11299
+ },
11300
+ {
11301
+ rule: "guidance-template-marker",
11302
+ pattern: /\{\{\s*[#/]\s*(?:system|assistant|user|tool|function)\s*~?\s*\}\}/i,
11303
+ severity: "medium",
11304
+ description: "guidance/handlebars role-block marker forgery ({{#system~}} ...)"
11305
+ },
11306
+ {
11307
+ rule: "markdown-system-link-spoof",
11308
+ pattern: /\[\s*(?:system|admin|root|assistant)\s*\]\s*\(\s*#(?:assistant|context|system|root|admin)\s*\)/i,
11309
+ severity: "medium",
11310
+ description: "Markdown link forgery spoofing a role marker ([system](#assistant))"
11311
+ },
10564
11312
  // --- LOW severity: ambiguous but worth flagging in strict mode ---
10565
11313
  {
10566
11314
  rule: "from-now-on",
@@ -11114,6 +11862,6 @@ function createRedisStore(options) {
11114
11862
  return new RedisStore(options);
11115
11863
  }
11116
11864
 
11117
- export { ArcisError, ValidationError as ArcisValidationError, BLOCKED, CorrelationWindow, ERRORS, Guards, HEADERS, INPUT, InputTooLargeError, MemoryStore, RATE_LIMIT, REDACTION, RateLimitError, RedisStore, ResponseSplittingError, SanitizationError, SecurityThreatError, TelemetryClient, TelemetryHttpError, VALIDATION, arcis, arcisWithMethods as arcisFunction, botProtection, checkSignup, createCors, createCsrf, createErrorHandler, createHeaders, createHpp, createRateLimiter, createRedactor, createRedisStore, createSafeLogger, createSanitizer, createSecureCookies, createSlidingWindowLimiter, createTokenBucketLimiter, createValidator, csrfProtection, main_default as default, detectBot, detectClientIp, detectCommandInjection, detectGraphqlAbuse, detectHeaderInjection, detectJsonpInjection, detectNoSqlInjection, detectPathTraversal, detectPii, detectPromptInjection, detectPrototypePollution, detectResponseSplitting, detectSql, detectSsti, detectXss, detectXxe, encodeForAttribute, encodeForCss, encodeForHtml, encodeForJs, encodeForUrl, enforceSecureCookie, errorHandler, eventLoopProtection, fingerprint, formatDuration, generateCsrfToken, graphqlGuard, hpp, inspectGraphqlQuery, isDangerousExtension, isDangerousNoSqlKey, isDangerousProtoKey, isPrivateIp, isRedirectSafe, isUrlSafe, isValidEmailSyntax, massAssign, methodAllowlist, parseDuration, pinnedDnsLookup, protectApi, protectLogin, protectSignup, rateLimit, redactObjectPii, redactPii, responseSplittingGuard, safeCors, safeFollowRedirect, safeLog, sanitizeCommand, sanitizeFilename, sanitizeHeaderValue, sanitizeHeaders, sanitizeJsonpCallback, sanitizeObject, sanitizePath, sanitizePromptInjection, sanitizeResponseHeader, sanitizeSql, sanitizeSsti, sanitizeString, sanitizeXss, sanitizeXxe, scanObjectPii, scanPii, secureCookieDefaults, securityHeaders, signupProtection, tokenBudget, validate, validateCsrfToken, validateEmail, validateFile, validateRedirect, validateUrl, validateUrlAsync, verifyEmailMx };
11865
+ export { ArcisError, ValidationError as ArcisValidationError, BLOCKED, CorrelationWindow, ERRORS, Guards, HEADERS, INPUT, InputTooLargeError, MemoryStore, RATE_LIMIT, REDACTION, RateLimitError, RedisStore, ResponseSplittingError, SanitizationError, SecurityThreatError, TelemetryClient, TelemetryHttpError, VALIDATION, arcis, arcisWithMethods as arcisFunction, botProtection, bruteForceProtection, checkSignup, createCors, createCsrf, createErrorHandler, createHeaders, createHpp, createRateLimiter, createRedactor, createRedisStore, createSafeLogger, createSanitizer, createSecureCookies, createSlidingWindowLimiter, createTokenBucketLimiter, createValidator, csrfProtection, main_default as default, detectBot, detectClientIp, detectCommandInjection, detectGraphqlAbuse, detectHeaderInjection, detectJsonpInjection, detectNoSqlInjection, detectPathTraversal, detectPii, detectPromptInjection, detectPrototypePollution, detectResponseSplitting, detectSql, detectSsti, detectXss, detectXxe, encodeForAttribute, encodeForCss, encodeForHtml, encodeForJs, encodeForUrl, enforceSecureCookie, errorHandler, eventLoopProtection, fingerprint, formatDuration, generateCsrfToken, graphqlGuard, hpp, inspectGraphqlQuery, isDangerousExtension, isDangerousNoSqlKey, isDangerousProtoKey, isPrivateIp, isRedirectSafe, isUrlSafe, isValidEmailSyntax, massAssign, methodAllowlist, parseDuration, pinnedDnsLookup, protectApi, protectLogin, protectSignup, rateLimit, redactObjectPii, redactPii, responseSplittingGuard, safeCors, safeFollowRedirect, safeLog, sanitizeCommand, sanitizeFilename, sanitizeHeaderValue, sanitizeHeaders, sanitizeJsonpCallback, sanitizeObject, sanitizePath, sanitizePromptInjection, sanitizeResponseHeader, sanitizeSql, sanitizeSsti, sanitizeString, sanitizeXss, sanitizeXxe, scanObjectPii, scanPii, secureCookieDefaults, securityHeaders, signupProtection, tokenBudget, validate, validateCsrfToken, validateEmail, validateFile, validateRedirect, validateUrl, validateUrlAsync, verifyEmailMx };
11118
11866
  //# sourceMappingURL=index.mjs.map
11119
11867
  //# sourceMappingURL=index.mjs.map