mdefender-pro 1.2.5 → 1.2.7

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 CHANGED
@@ -10,11 +10,11 @@
10
10
 
11
11
  ## Key Features
12
12
 
13
- - 🛡️ **Zero Setup Cyber Block Page**: Bundled automatically with the package — no external HTML or static file hosting required.
14
- - ⚡ **Sub-Millisecond In-Memory Caching**: Template and rules are cached in memory for instantaneous rendering (<5ms).
15
- - 🔑 **Flexible API Key Authentication**: Configure via `mdefender.config.js`, interactive CLI (`npx mdefender-pro init`), environment variables, or inline parameters.
16
- - 🚦 **Fail-Open Safety Mechanism**: If cloud telemetry times out, legitimate traffic passes smoothly without blocking customers.
17
- - 📦 **Zero External Runtime Dependencies**: Pure Node.js standard libraries (`http`, `https`, `crypto`).
13
+ - **Zero Setup Cyber Block Page**: Bundled automatically with the package &mdash; no external HTML or static file hosting required.
14
+ - **Sub-Millisecond In-Memory Caching**: Template and rules are cached in memory for instantaneous rendering (<5ms).
15
+ - **Flexible API Key Authentication**: Configure via `mdefender.config.js`, interactive CLI (`npx mdefender-pro init`), environment variables, or inline parameters.
16
+ - **Fail-Open Safety Mechanism**: If cloud telemetry times out, legitimate traffic passes smoothly without blocking customers.
17
+ - **Zero External Runtime Dependencies**: Pure Node.js standard libraries (`http`, `https`, `crypto`).
18
18
 
19
19
  ---
20
20
 
package/auto.js CHANGED
@@ -35,7 +35,7 @@ function autoHook() {
35
35
  return;
36
36
  }
37
37
 
38
- console.log(`\x1b[36m\x1b[1m🛡️ [MDefender Pro] Zero-Code WAF Protection Active\x1b[0m`);
38
+ console.log(`\x1b[36m\x1b[1m[MDefender Pro] Zero-Code WAF Protection Active\x1b[0m`);
39
39
  console.log(`\x1b[90m Inspection Endpoint: ${activeConfig.apiEndpoint}\x1b[0m`);
40
40
  console.log(`\x1b[90m Protected Domain : ${activeConfig.domain || 'auto-detect'}\x1b[0m`);
41
41
  console.log(`\x1b[90m Defense Mode : ${activeConfig.mode.toUpperCase()}\x1b[0m\n`);
package/bin/mdefender.js CHANGED
@@ -9,7 +9,7 @@ const args = process.argv.slice(2);
9
9
  const command = args[0] || 'help';
10
10
 
11
11
  console.log(`\n\x1b[36m\x1b[1m====================================================\x1b[0m`);
12
- console.log(`\x1b[36m\x1b[1m 🛡️ MDefender Pro — Zero-Code WAF CLI \x1b[0m`);
12
+ console.log(`\x1b[36m\x1b[1m MDefender Pro — Zero-Code WAF CLI \x1b[0m`);
13
13
  console.log(`\x1b[36m\x1b[1m====================================================\x1b[0m\n`);
14
14
 
15
15
  if (command === 'run' || command === 'start') {
package/block-page.html CHANGED
@@ -369,7 +369,7 @@
369
369
  const refBox = document.getElementById('ref-id-box');
370
370
  if (refBox) {
371
371
  const originalHtml = refBox.innerHTML;
372
- refBox.innerHTML = 'COPIED TO CLIPBOARD! ✅';
372
+ refBox.innerHTML = 'COPIED TO CLIPBOARD';
373
373
  refBox.style.color = '#10b981';
374
374
  refBox.style.borderColor = '#10b981';
375
375
  refBox.style.background = '#ecfdf5';
package/client.mjs CHANGED
@@ -463,18 +463,7 @@ export function renderOfficialBlockPage(attackType, refId, domain) {
463
463
  } catch (e) {}
464
464
  }
465
465
 
466
- // 0ms Instant URL Inspection on Script Load
467
- if (typeof window !== 'undefined' && typeof document !== 'undefined') {
468
- const rawTarget = normalizeInput(window.location.search + ' ' + window.location.hash);
469
- if (rawTarget.trim()) {
470
- for (const pattern of ATTACK_PATTERNS) {
471
- if (pattern.regex.test(rawTarget)) {
472
- renderOfficialBlockPage(pattern.type);
473
- throw new Error(`[MDefender WAF] Attack blocked on load (0ms): ${pattern.type}`);
474
- }
475
- }
476
- }
477
- }
466
+ // Client-side initialization requires explicit initWaf() with apiKey
478
467
 
479
468
  /**
480
469
  * Initialize MDefender Pro WAF client-side protection for SPAs & Frontend Websites.
@@ -492,6 +481,20 @@ export function initWaf(options = {}) {
492
481
  const backendUrl = (options.backendUrl || 'http://localhost:8000').replace(/\/+$/, '');
493
482
  const domain = options.domain || window.location.hostname || 'localhost';
494
483
 
484
+ // 0. Auto-inspect current page URL on load (e.g. ?q=<script> or ?id=1 UNION SELECT)
485
+ try {
486
+ const currentUrlParams = (window.location.search || '') + ' ' + (window.location.hash || '');
487
+ if (currentUrlParams.trim()) {
488
+ const normUrl = normalizeInput(currentUrlParams);
489
+ for (const pattern of ATTACK_PATTERNS) {
490
+ if (pattern.regex.test(normUrl)) {
491
+ renderOfficialBlockPage(pattern.type, null, domain);
492
+ return;
493
+ }
494
+ }
495
+ }
496
+ } catch (e) {}
497
+
495
498
  // 1. Wrap window.fetch for outgoing requests
496
499
  const originalFetch = window.fetch;
497
500
  window.fetch = async (input, init, ...args) => {
@@ -502,6 +505,7 @@ export function initWaf(options = {}) {
502
505
  else if (url.includes('#')) targetParamStr = url.substring(url.indexOf('#'));
503
506
  } catch (e) {}
504
507
 
508
+ // Inspect URL
505
509
  if (targetParamStr) {
506
510
  const normParams = normalizeInput(targetParamStr);
507
511
  for (const pattern of ATTACK_PATTERNS) {
@@ -512,14 +516,36 @@ export function initWaf(options = {}) {
512
516
  }
513
517
  }
514
518
 
519
+ // Inspect Body if POST/PUT
520
+ if (init && init.body) {
521
+ try {
522
+ const bodyStr = typeof init.body === 'string' ? init.body : JSON.stringify(init.body);
523
+ const normBody = normalizeInput(bodyStr);
524
+ for (const pattern of ATTACK_PATTERNS) {
525
+ if (pattern.regex.test(normBody)) {
526
+ renderOfficialBlockPage(pattern.type, null, domain);
527
+ throw new Error(`[MDefender WAF] Outgoing payload attack blocked: ${pattern.type}`);
528
+ }
529
+ }
530
+ } catch (e) {}
531
+ }
532
+
515
533
  try {
516
534
  const response = await originalFetch(input, init, ...args);
517
535
  if (response.status === 403) {
518
536
  const clone = response.clone();
519
537
  try {
520
538
  const text = await clone.text();
521
- if (text.includes('403') && (text.includes('MDefender') || text.includes('Access Denied'))) {
522
- renderOfficialBlockPage('Cross-Site Scripting (XSS)', null, domain);
539
+ const statusHeader = response.headers.get('x-mdefender-status');
540
+ const attackHeader = response.headers.get('x-mdefender-attack-type');
541
+ const refHeader = response.headers.get('x-mdefender-ref');
542
+ if (statusHeader === 'blocked' || text.includes('403') || text.includes('MDefender') || text.includes('Access Denied')) {
543
+ if (text.includes('<!DOCTYPE html>') || text.includes('<html')) {
544
+ try { window.stop(); } catch (e) {}
545
+ document.documentElement.innerHTML = text;
546
+ } else {
547
+ renderOfficialBlockPage(attackHeader || 'Cross-Site Scripting (XSS)', refHeader, domain);
548
+ }
523
549
  }
524
550
  } catch (e) {}
525
551
  }
@@ -529,7 +555,7 @@ export function initWaf(options = {}) {
529
555
  }
530
556
  };
531
557
 
532
- // 2. Wrap XMLHttpRequest
558
+ // 2. Wrap XMLHttpRequest (Used by Axios, Redux Toolkit Query, etc.)
533
559
  const originalOpen = XMLHttpRequest.prototype.open;
534
560
  XMLHttpRequest.prototype.open = function (method, url, ...rest) {
535
561
  let targetParamStr = '';
@@ -549,6 +575,44 @@ export function initWaf(options = {}) {
549
575
  }
550
576
  return originalOpen.apply(this, [method, url, ...rest]);
551
577
  };
578
+
579
+ const originalSend = XMLHttpRequest.prototype.send;
580
+ XMLHttpRequest.prototype.send = function (body) {
581
+ if (body) {
582
+ try {
583
+ const bodyStr = typeof body === 'string' ? body : JSON.stringify(body);
584
+ const normBody = normalizeInput(bodyStr);
585
+ for (const pattern of ATTACK_PATTERNS) {
586
+ if (pattern.regex.test(normBody)) {
587
+ renderOfficialBlockPage(pattern.type, null, domain);
588
+ throw new Error(`[MDefender WAF] XHR payload attack blocked: ${pattern.type}`);
589
+ }
590
+ }
591
+ } catch (e) {}
592
+ }
593
+
594
+ // Intercept 403 Forbidden responses from backend WAF
595
+ this.addEventListener('load', function () {
596
+ if (this.status === 403) {
597
+ try {
598
+ const resp = this.responseText || '';
599
+ const statusHeader = this.getResponseHeader('X-MDefender-Status');
600
+ const attackHeader = this.getResponseHeader('X-MDefender-Attack-Type');
601
+ const refHeader = this.getResponseHeader('X-MDefender-Ref');
602
+ if (statusHeader === 'blocked' || resp.includes('403') || resp.includes('MDefender') || resp.includes('Access Denied')) {
603
+ if (resp.includes('<!DOCTYPE html>') || resp.includes('<html')) {
604
+ try { window.stop(); } catch (e) {}
605
+ document.documentElement.innerHTML = resp;
606
+ } else {
607
+ renderOfficialBlockPage(attackHeader || 'Security Rule Violation', refHeader, domain);
608
+ }
609
+ }
610
+ } catch (e) {}
611
+ }
612
+ });
613
+
614
+ return originalSend.apply(this, arguments);
615
+ };
552
616
  }
553
617
 
554
618
  export default { initWaf, renderOfficialBlockPage };
package/index.js CHANGED
@@ -158,7 +158,7 @@ function sendAnalyzeRequest(endpointUrl, apiKey, data, timeoutMs = 5000) {
158
158
  'Content-Type': 'application/json',
159
159
  'Content-Length': Buffer.byteLength(postData),
160
160
  'Authorization': `Bearer ${apiKey}`,
161
- 'X-MDefender-Version': '1.2.4'
161
+ 'X-MDefender-Version': '1.2.6'
162
162
  }
163
163
  };
164
164
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mdefender-pro",
3
- "version": "1.2.5",
3
+ "version": "1.2.7",
4
4
  "description": "MDefender Pro - Web Application Firewall middleware for Node.js/Express. Protects against XSS, SQLi, CSRF, and other OWASP Top 10 attacks.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",