wolfguard-next-waf 1.0.0

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 ADDED
@@ -0,0 +1,178 @@
1
+
2
+ # đŸē WolfGuard WAF for Next.js
3
+
4
+ A lightweight, edge-optimized Web Application Firewall (WAF) built specifically for Next.js Middleware.
5
+
6
+ WolfGuard helps protect your application against common Layer-7 attacks by combining threat signature detection, rate limiting, automated IP banning, and real-time security telemetry.
7
+
8
+ ## ✨ Features
9
+ - **⚡ Edge Runtime Compatible**
10
+ - **đŸ›Ąī¸ Layer-7 Threat Detection**
11
+ - **đŸ¯ Honeypot Scanner Detection**
12
+ - **đŸšĻ Configurable Rate Limiting**
13
+ - **🔨 Automatic Temporary IP Banning**
14
+ - **📡 Discord SOC Alerting**
15
+ - **🧩 Whitelist & Blacklist Support**
16
+ - **đŸĒļ Zero External Runtime Dependencies**
17
+
18
+ <p align="center">
19
+ <img src="./architecture.svg" alt="WolfGuard Architecture Flow" width="100%">
20
+ </p>
21
+
22
+ ---
23
+
24
+ ## đŸ“Ļ Installation
25
+
26
+ ```bash
27
+ npm install wolfguard-next-waf
28
+
29
+ ```
30
+
31
+ *Also supports `yarn add` and `pnpm add`.*
32
+
33
+ ---
34
+
35
+ ## 🚀 Quick Start
36
+
37
+ Secure your entire application in three lines of code. Create or update your `middleware.js` file:
38
+
39
+ ```javascript
40
+ import { WolfGuardWAF } from "wolfguard-next-waf";
41
+
42
+ const waf = new WolfGuardWAF();
43
+
44
+ export async function middleware(request) {
45
+ return await waf.execute(request);
46
+ }
47
+
48
+ export const config = {
49
+ matcher: [
50
+ "/((?!_next/static|_next/image|favicon.ico).*)"
51
+ ]
52
+ };
53
+
54
+ ```
55
+
56
+ ---
57
+
58
+ ## âš™ī¸ Advanced Configuration
59
+
60
+ Customize the WAF to fit your exact threat model by passing a configuration object.
61
+
62
+ ```javascript
63
+ import { WolfGuardWAF } from "wolfguard-next-waf";
64
+
65
+ const waf = new WolfGuardWAF({
66
+ discordWebhook: process.env.DISCORD_WEBHOOK,
67
+
68
+ rateLimit: 100,
69
+ timeWindow: 60 * 1000,
70
+ banDuration: 24 * 60 * 60 * 1000,
71
+
72
+ whitelist: ["192.168.1.10", "10.0.0.5"],
73
+ blacklist: ["185.15.59.224"],
74
+
75
+ customRules: [
76
+ { regex: /eval\(/i, type: "Malicious Eval Injection" }
77
+ ]
78
+ });
79
+
80
+ export async function middleware(request) {
81
+ return await waf.execute(request);
82
+ }
83
+
84
+ ```
85
+
86
+ ### 📖 Configuration Reference
87
+
88
+ | Option | Type | Default | Description |
89
+ | --- | --- | --- | --- |
90
+ | `discordWebhook` | `string` | `null` | Discord webhook URL for real-time security alerts. |
91
+ | `rateLimit` | `number` | `50` | Maximum requests allowed during the tracking window. |
92
+ | `timeWindow` | `number` | `60000` | Tracking window in milliseconds. |
93
+ | `banDuration` | `number` | `86400000` | Temporary ban duration in milliseconds. |
94
+ | `whitelist` | `string[]` | `[]` | IP addresses that bypass all security checks. |
95
+ | `blacklist` | `string[]` | `[]` | Permanently blocked IP addresses. |
96
+ | `customRules` | `object[]` | `[]` | Array of custom Regex rules for threat detection. |
97
+
98
+ ---
99
+
100
+ ## đŸ›Ąī¸ Built-in Threat Detection
101
+
102
+ WolfGuard currently detects and blocks:
103
+
104
+ * **Cross-Site Scripting (XSS)** (`<script>alert(1)</script>`)
105
+ * **SQL Injection (SQLi)** (`UNION SELECT username,password FROM users`)
106
+ * **Path Traversal (LFI)** (`../../etc/passwd`)
107
+ * **OS Command Injection** (`; bash -i`)
108
+ * **Sensitive File Enumeration** (`.env`, `.git`, `config.yaml`, `backup.sql`)
109
+ * **Admin Panel Scanners** (`/wp-admin`, `/phpmyadmin`, `/admin.php`)
110
+
111
+ ---
112
+
113
+ ## đŸšĻ Rate Limiting
114
+
115
+ WolfGuard includes a built-in, edge-safe, in-memory rate limiter with probabilistic garbage collection to prevent memory leaks.
116
+
117
+ Requests are tracked per IP. If the limit is exceeded, the IP is automatically banned for the configured `banDuration`, and future requests instantly receive an HTTP `429 Too Many Requests` status.
118
+
119
+ ---
120
+
121
+ ## 📡 Discord Security Operations Center (SOC) Alerts
122
+
123
+ When an attack is detected, WolfGuard sends a detailed, throttled alert to your private Discord channel, including:
124
+
125
+ * Threat Classification
126
+ * Target URI
127
+ * Attacker IP Address
128
+ * ISP Information
129
+ * Geo-Location & Coordinates
130
+ * User-Agent Information
131
+
132
+ This enables lightweight SOC-style monitoring without requiring expensive SIEM infrastructure.
133
+
134
+ ---
135
+
136
+ ## 📁 Project Structure
137
+
138
+ ```text
139
+ wolfguard-next-waf/
140
+ ├── src/
141
+ │ ├── index.js
142
+ │ ├── rateLimiter.js
143
+ │ ├── signatures.js
144
+ │ ├── telemetry.js
145
+ │ └── utils.js
146
+ ├── package.json
147
+ ├── README.md
148
+ └── LICENSE
149
+
150
+ ```
151
+
152
+ ---
153
+
154
+ ## 🔒 Security Notes
155
+
156
+ WolfGuard is intended to be an *additional* security layer and should not replace secure coding practices, input validation, or authentication controls. For production deployments, WolfGuard should be used alongside network-level protection such as Cloudflare or AWS Shield.
157
+
158
+ ---
159
+
160
+ ## đŸ› ī¸ Roadmap
161
+
162
+ * Redis-backed distributed rate limiting
163
+ * IP reputation intelligence (AbuseIPDB integration)
164
+ * Express.js and Fastify adapters
165
+ * Cloudflare Workers adapter
166
+
167
+ ---
168
+
169
+ ## 🤝 Contributing
170
+
171
+ Contributions, bug reports, and feature requests are welcome. If you discover a security issue, please open a private issue before submitting a public disclosure.
172
+
173
+ ## 📄 License
174
+
175
+ MIT License
176
+ Copyright (c) 2026 Pugazhmani K.
177
+
178
+
@@ -0,0 +1,52 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 400" width="100%" height="100%">
2
+ <rect width="800" height="400" fill="#0f172a" rx="10"/>
3
+
4
+ <pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
5
+ <path d="M 40 0 L 0 0 0 40" fill="none" stroke="#1e293b" stroke-width="1"/>
6
+ </pattern>
7
+ <rect width="800" height="400" fill="url(#grid)" rx="10"/>
8
+
9
+ <defs>
10
+ <marker id="arrowGreen" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
11
+ <path d="M 0 0 L 10 5 L 0 10 z" fill="#10b981" />
12
+ </marker>
13
+ <marker id="arrowRed" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
14
+ <path d="M 0 0 L 10 5 L 0 10 z" fill="#ef4444" />
15
+ </marker>
16
+ <marker id="arrowBlue" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
17
+ <path d="M 0 0 L 10 5 L 0 10 z" fill="#3b82f6" />
18
+ </marker>
19
+ </defs>
20
+
21
+ <path d="M 150 200 L 285 200" stroke="#3b82f6" stroke-width="3" fill="none" marker-end="url(#arrowBlue)" stroke-dasharray="5,5"/>
22
+ <path d="M 500 180 L 620 100" stroke="#ef4444" stroke-width="3" fill="none" marker-end="url(#arrowRed)"/>
23
+ <path d="M 500 220 L 620 300" stroke="#10b981" stroke-width="3" fill="none" marker-end="url(#arrowGreen)"/>
24
+
25
+ <rect x="30" y="160" width="120" height="80" rx="8" fill="#1e293b" stroke="#3b82f6" stroke-width="2"/>
26
+ <text x="90" y="195" fill="#f8fafc" font-family="sans-serif" font-size="16" font-weight="bold" text-anchor="middle">Public Web</text>
27
+ <text x="90" y="215" fill="#94a3b8" font-family="sans-serif" font-size="12" text-anchor="middle">Incoming Traffic</text>
28
+
29
+ <rect x="300" y="120" width="200" height="160" rx="8" fill="#020617" stroke="#8b5cf6" stroke-width="3"/>
30
+ <text x="400" y="160" fill="#f8fafc" font-family="sans-serif" font-size="18" font-weight="bold" text-anchor="middle">WolfGuard WAF</text>
31
+ <text x="400" y="185" fill="#a78bfa" font-family="sans-serif" font-size="14" text-anchor="middle">(Next.js Middleware)</text>
32
+
33
+ <rect x="330" y="205" width="140" height="24" rx="4" fill="#1e1b4b"/>
34
+ <text x="400" y="222" fill="#c4b5fd" font-family="sans-serif" font-size="11" font-weight="bold" text-anchor="middle">Regex Signatures</text>
35
+
36
+ <rect x="330" y="235" width="140" height="24" rx="4" fill="#1e1b4b"/>
37
+ <text x="400" y="252" fill="#c4b5fd" font-family="sans-serif" font-size="11" font-weight="bold" text-anchor="middle">Token Bucket Limiter</text>
38
+
39
+ <rect x="620" y="60" width="150" height="80" rx="8" fill="#1e293b" stroke="#ef4444" stroke-width="2"/>
40
+ <text x="695" y="95" fill="#f8fafc" font-family="sans-serif" font-size="16" font-weight="bold" text-anchor="middle">Discord SOC</text>
41
+ <text x="695" y="115" fill="#fca5a5" font-family="sans-serif" font-size="12" text-anchor="middle">Real-Time Alerts</text>
42
+
43
+ <rect x="520" y="110" width="80" height="20" rx="10" fill="#ef4444"/>
44
+ <text x="560" y="124" fill="#ffffff" font-family="sans-serif" font-size="10" font-weight="bold" text-anchor="middle">BLOCKED (403)</text>
45
+
46
+ <rect x="620" y="260" width="150" height="80" rx="8" fill="#1e293b" stroke="#10b981" stroke-width="2"/>
47
+ <text x="695" y="295" fill="#f8fafc" font-family="sans-serif" font-size="16" font-weight="bold" text-anchor="middle">Next.js App</text>
48
+ <text x="695" y="315" fill="#6ee7b7" font-family="sans-serif" font-size="12" text-anchor="middle">Safe Rendering</text>
49
+
50
+ <rect x="520" y="275" width="80" height="20" rx="10" fill="#10b981"/>
51
+ <text x="560" y="289" fill="#ffffff" font-family="sans-serif" font-size="10" font-weight="bold" text-anchor="middle">PASSED (200)</text>
52
+ </svg>
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "wolfguard-next-waf",
3
+ "version": "1.0.0",
4
+ "description": "An edge-optimized Web Application Firewall (WAF), rate-limiter, and real-time SOC telemetry pipeline for Next.js Middleware.",
5
+ "main": "src/index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "test": "echo \"Error: no test specified\" && exit 0"
9
+ },
10
+ "keywords": [
11
+ "nextjs",
12
+ "middleware",
13
+ "waf",
14
+ "firewall",
15
+ "rate-limiting",
16
+ "security",
17
+ "owasp",
18
+ "discord-webhook",
19
+ "soc-telemetry"
20
+ ],
21
+ "author": "Pugazhmani K.",
22
+ "license": "MIT",
23
+ "engines": {
24
+ "node": ">=18.0.0"
25
+ },
26
+ "peerDependencies": {
27
+ "next": ">=13.0.0"
28
+ }
29
+ }
package/src/index.js ADDED
@@ -0,0 +1,104 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { extractClientIp } from './utils.js';
3
+ import { detectThreat } from './signatures.js';
4
+ import { RateLimiter } from './rateLimiter.js';
5
+ import { dispatchSocAlert } from './telemetry.js';
6
+
7
+ /**
8
+ * WolfGuardWAF - The main entry point wrapper for edge-optimized protection.
9
+ */
10
+ export class WolfGuardWAF {
11
+ /**
12
+ * @param {Object} config - Custom configuration options for the firewall.
13
+ * @param {string} config.discordWebhook - Your private Discord SIEM channel webhook URL.
14
+ * @param {number} config.rateLimit - Max allowed requests per window before temporary ban.
15
+ * @param {number} config.timeWindow - Tracking time window in milliseconds (Default: 1 min).
16
+ * @param {number} config.banDuration - Punitive network block duration in milliseconds (Default: 24h).
17
+ * @param {Array<string>} config.whitelist - Array of IP addresses explicitly immune to restrictions.
18
+ * @param {Array<string>} config.blacklist - Array of IP addresses permanently dropped.
19
+ * @param {Array<Object>} config.customRules - Custom Regex threat signatures provided by the developer.
20
+ */
21
+ constructor(config = {}) {
22
+ this.discordWebhook = config.discordWebhook || null;
23
+ this.whitelist = new Set(config.whitelist || []);
24
+ this.blacklist = new Set(config.blacklist || []);
25
+ this.customRules = config.customRules || [];
26
+
27
+ // Anti-Spam: Prevents sending 1000 Discord alerts if an attacker spams a payload
28
+ this.alertCooldowns = new Map();
29
+
30
+ // Initialize the internal rate limiting state instance
31
+ const limit = config.rateLimit || 50;
32
+ const windowMs = config.timeWindow || 60000;
33
+ const banMs = config.banDuration || 86400000;
34
+ this.limiter = new RateLimiter(limit, windowMs, banMs);
35
+ }
36
+
37
+ /**
38
+ * The primary interceptor function meant to run inside Next.js edge middleware.
39
+ * @param {Request} request - The standard incoming Next.js Request object.
40
+ * @returns {Promise<NextResponse>} Next.js execution path alteration instructions.
41
+ */
42
+ async execute(request) {
43
+ const ip = extractClientIp(request);
44
+ // Include query parameters in the path to catch SQLi in URLs (e.g., ?id=1 UNION SELECT)
45
+ const path = request.nextUrl.pathname + request.nextUrl.search;
46
+ const userAgent = request.headers.get("user-agent") || "Missing User-Agent Context";
47
+
48
+ // 1. Evaluate Explicit Perma-Blacklist Constraints
49
+ if (this.blacklist.has(ip)) {
50
+ return new NextResponse(
51
+ JSON.stringify({ error: "FORBIDDEN", message: "IP network node permanently blacklisted." }),
52
+ { status: 403, headers: { 'content-type': 'application/json' } }
53
+ );
54
+ }
55
+
56
+ // 2. Evaluate Whitelist Exemption Strategy
57
+ if (this.whitelist.has(ip)) {
58
+ return NextResponse.next();
59
+ }
60
+
61
+ // 3. Layer-7 Threat Signature & Honeypot Assessment (Includes Developer Custom Rules)
62
+ const detectedThreatType = detectThreat(path, this.customRules);
63
+ if (detectedThreatType) {
64
+ this.triggerAlert(detectedThreatType, path, ip, userAgent);
65
+ return new NextResponse(
66
+ JSON.stringify({ error: "SECURITY_INTERCEPT", message: "Malicious signature vector detected." }),
67
+ { status: 403, headers: { 'content-type': 'application/json' } }
68
+ );
69
+ }
70
+
71
+ // 4. Rate Limiter Velocity & Flood Assessment
72
+ const rateCheck = this.limiter.checkLimit(ip);
73
+ if (rateCheck.blocked) {
74
+ if (rateCheck.reason === "RATE_LIMIT_EXCEEDED") {
75
+ this.triggerAlert("Volumetric Flood Detect (Auto-Ban Enforced)", path, ip, userAgent);
76
+ }
77
+ return new NextResponse(
78
+ JSON.stringify({ error: "TOO_MANY_REQUESTS", message: "Rate limit exceeded. Temporary lockout active." }),
79
+ { status: 429, headers: { 'content-type': 'application/json' } }
80
+ );
81
+ }
82
+
83
+ // If all checks pass clean, allow the request to flow through normally
84
+ return NextResponse.next();
85
+ }
86
+
87
+ /**
88
+ * Internal proxy to forward telemetry events cleanly to the telemetry pipeline.
89
+ * @private
90
+ */
91
+ triggerAlert(threatType, path, ip, userAgent) {
92
+ if (!this.discordWebhook) return;
93
+
94
+ // Alert Throttling: Only alert Discord once per IP every 60 seconds
95
+ const lastAlert = this.alertCooldowns.get(ip) || 0;
96
+ if (Date.now() - lastAlert < 60000) return;
97
+
98
+ this.alertCooldowns.set(ip, Date.now());
99
+
100
+ // Execute async dispatch without awaiting to prevent latency blocks for the end-user
101
+ dispatchSocAlert(this.discordWebhook, { threatType, path, ip, userAgent })
102
+ .catch((err) => console.error("[WolfGuard WAF] Async alerting failure:", err));
103
+ }
104
+ }
@@ -0,0 +1,53 @@
1
+ export class RateLimiter {
2
+ constructor(limit = 50, windowMs = 60000, banMs = 86400000) {
3
+ this.limit = limit;
4
+ this.windowMs = windowMs;
5
+ this.banMs = banMs;
6
+ this.requestTracker = new Map();
7
+ this.tempBans = new Map();
8
+ }
9
+
10
+ // Serverless Garbage Collection to prevent Memory Leaks
11
+ cleanup() {
12
+ const now = Date.now();
13
+ for (const [ip, data] of this.requestTracker) {
14
+ if (now > data.resetTime) this.requestTracker.delete(ip);
15
+ }
16
+ for (const [ip, unbanTime] of this.tempBans) {
17
+ if (now > unbanTime) this.tempBans.delete(ip);
18
+ }
19
+ }
20
+
21
+ checkLimit(ip) {
22
+ const now = Date.now();
23
+
24
+ // Probabilistic Cleanup: Runs on ~2% of requests to keep memory clean at the Edge
25
+ if (Math.random() < 0.02) this.cleanup();
26
+
27
+ if (this.tempBans.has(ip)) {
28
+ if (now > this.tempBans.get(ip)) {
29
+ this.tempBans.delete(ip);
30
+ } else {
31
+ return { blocked: true, reason: "AUTO_BANNED" };
32
+ }
33
+ }
34
+
35
+ let ipData = this.requestTracker.get(ip) || { count: 0, resetTime: now + this.windowMs };
36
+
37
+ if (now > ipData.resetTime) {
38
+ ipData = { count: 1, resetTime: now + this.windowMs };
39
+ } else {
40
+ ipData.count += 1;
41
+ }
42
+
43
+ this.requestTracker.set(ip, ipData);
44
+
45
+ if (ipData.count > this.limit) {
46
+ this.tempBans.set(ip, now + this.banMs);
47
+ this.requestTracker.delete(ip);
48
+ return { blocked: true, reason: "RATE_LIMIT_EXCEEDED" };
49
+ }
50
+
51
+ return { blocked: false, reason: null };
52
+ }
53
+ }
@@ -0,0 +1,30 @@
1
+ export const DEFAULT_SIGNATURES = [
2
+ { regex: /(%3C|<)script(%3E|>)/i, type: "XSS (Cross-Site Scripting)" },
3
+ { regex: /UNION.+SELECT|SELECT.+FROM/i, type: "SQL Injection (SQLi)" },
4
+ { regex: /(\.\.\/|\.\.\\)/i, type: "Path Traversal (LFI)" },
5
+ { regex: /\.(env|git|bak|sql|php|yaml|config|pem|key)$/i, type: "Sensitive File Honeypot" },
6
+ { regex: /(wp-admin|phpmyadmin|admin\.php)/i, type: "Admin Panel Honeypot" },
7
+ { regex: /(\$|%24)\{.*?\}/i, type: "Template Injection (SSTI)" },
8
+ { regex: /(;|\||&&|`|%60).*(bash|sh|wget|curl|nc|ping)/i, type: "OS Command Injection" }
9
+ ];
10
+
11
+ export function detectThreat(urlPath, customSignatures = []) {
12
+ // 1. Sanitize and Normalize the Input to prevent bypasses
13
+ let normalizedPath = urlPath;
14
+ try {
15
+ normalizedPath = decodeURIComponent(urlPath).toLowerCase();
16
+ } catch (e) {
17
+ // If decoding fails, it's likely a malformed payload anyway
18
+ normalizedPath = urlPath.toLowerCase();
19
+ }
20
+
21
+ // 2. Combine default and developer-provided custom rules
22
+ const allSignatures = [...DEFAULT_SIGNATURES, ...customSignatures];
23
+
24
+ for (const signature of allSignatures) {
25
+ if (signature.regex.test(normalizedPath) || signature.regex.test(urlPath)) {
26
+ return signature.type;
27
+ }
28
+ }
29
+ return null;
30
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Queries a secure, HTTPS IP geolocation API to resolve ISP and coordinate telemetry.
3
+ * * @param {string} ip - Target IP address
4
+ * @returns {Promise<object>} Resolved geolocation and network data
5
+ */
6
+ async function fetchIpIntelligence(ip) {
7
+ // Prevent API thrashing and rate-limiting blocks during local testing
8
+ if (ip === "127.0.0.1" || ip === "::1" || ip.startsWith("192.168.")) {
9
+ return {
10
+ location: "Internal Security Sandbox (Localhost)",
11
+ coordinates: "N/A",
12
+ isp: "Local Loopback Interface"
13
+ };
14
+ }
15
+
16
+ try {
17
+ // Querying the endpoint with a strict 2-second timeout constraint
18
+ const controller = new AbortController();
19
+ const timeoutId = setTimeout(() => controller.abort(), 2000);
20
+
21
+ const response = await fetch(`https://ipwho.is/${ip}`, { signal: controller.signal });
22
+ clearTimeout(timeoutId);
23
+
24
+ if (response.ok) {
25
+ const data = await response.json();
26
+ if (data.success) {
27
+ return {
28
+ location: `${data.city || "Unknown City"}, ${data.region || "Unknown Region"}, ${data.country || "Unknown Country"}`,
29
+ coordinates: `${data.latitude || 0}, ${data.longitude || 0}`,
30
+ isp: data.connection.isp || data.connection.org || "Unknown ISP Provider"
31
+ };
32
+ }
33
+ }
34
+ } catch (error) {
35
+ // Silent mitigation to ensure a failed lookup doesn't crash the host application
36
+ console.error("[WolfGuard WAF] Threat intelligence lookup bypassed or timed out.");
37
+ }
38
+
39
+ return {
40
+ location: "Unknown Location (Lookup Failed)",
41
+ coordinates: "N/A",
42
+ isp: "Autonomous System / Hidden Proxy"
43
+ };
44
+ }
45
+
46
+ /**
47
+ * Compiles a detailed threat report and dispatches it via a structured Discord Webhook embed.
48
+ */
49
+ export async function dispatchSocAlert(webhookUrl, { threatType, path, ip, userAgent }) {
50
+ if (!webhookUrl) return;
51
+
52
+ // Sanitize and truncate data to prevent Discord payload injection errors (max length limits)
53
+ const safePath = path.substring(0, 300);
54
+ const safeUA = (userAgent || "Missing User-Agent Header").substring(0, 300);
55
+
56
+ // Resolve Geo-IP and ISP context before compiling report
57
+ const intel = await fetchIpIntelligence(ip);
58
+
59
+ const payload = {
60
+ username: "WolfGuard Active Defense Engine",
61
+ avatar_url: "https://images.unsplash.com/photo-1614064641938-3bbee52942c7?q=80&w=128&auto=format&fit=crop", // Abstract shield
62
+ embeds: [
63
+ {
64
+ title: "🚨 SEC-OPS: EDGE INTERCEPT DETECTED",
65
+ description: "The incoming network packet triggered a high-severity rule violation and was successfully dropped at the application perimeter.",
66
+ color: 16711680, // High-visibility red hex code
67
+ fields: [
68
+ { name: "đŸŽšī¸ Threat Classification", value: `**${threatType}**`, inline: false },
69
+ { name: "đŸŽ¯ Target URI Vector", value: `\`\`\`text\n${safePath}\n\`\`\``, inline: false },
70
+ { name: "🌐 Client IP Address", value: `\`${ip}\``, inline: true },
71
+ { name: "đŸĸ Network ISP Provider", value: intel.isp, inline: true },
72
+ { name: "📍 Geo-Location Matrix", value: intel.location, inline: true },
73
+ { name: "đŸ’ģ Device Identity String", value: `\`\`\`text\n${safeUA}\n\`\`\``, inline: false }
74
+ ],
75
+ footer: {
76
+ text: "System telemetry verified â€ĸ WolfGuard WAF Framework",
77
+ icon_url: "https://images.unsplash.com/photo-1614064641938-3bbee52942c7?q=80&w=128&auto=format&fit=crop"
78
+ },
79
+ timestamp: new Date().toISOString()
80
+ }
81
+ ]
82
+ };
83
+
84
+ try {
85
+ await fetch(webhookUrl, {
86
+ method: "POST",
87
+ headers: { "Content-Type": "application/json" },
88
+ body: JSON.stringify(payload)
89
+ });
90
+ } catch (err) {
91
+ console.error("[WolfGuard WAF] Failed to transmit alert vector to target SIEM channel.");
92
+ }
93
+ }
package/src/utils.js ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Safely extracts the client's public IP address from Next.js request headers.
3
+ * Accounts for edge proxies, load balancers, and local loopbacks.
4
+ * * @param {Request} request - The incoming Next.js Request object
5
+ * @returns {string} The resolved IP address
6
+ */
7
+ export function extractClientIp(request) {
8
+ // Check standard proxy headers populated by Vercel / Cloudflare
9
+ const xForwardedFor = request.headers.get("x-forwarded-for");
10
+ const xRealIp = request.headers.get("x-real-ip");
11
+
12
+ if (xForwardedFor) {
13
+ // x-forwarded-for can contain a comma-separated chain of IPs (client, proxy1, proxy2).
14
+ // The first IP in the list is always the original client.
15
+ const ipChain = xForwardedFor.split(",");
16
+ const clientIp = ipChain[0].trim();
17
+ if (clientIp) return clientIp;
18
+ }
19
+
20
+ if (xRealIp) {
21
+ return xRealIp.trim();
22
+ }
23
+
24
+ // Fallback if no proxy headers are present (e.g., raw local dev environment)
25
+ return "127.0.0.1";
26
+ }