z-shield 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +406 -2
- package/SECURITY.md +48 -0
- package/package.json +41 -4
- package/src/block-manager.js +326 -0
- package/src/cli.js +680 -0
- package/src/config.js +165 -0
- package/src/detector.js +88 -0
- package/src/index.js +97 -0
- package/src/logger.js +279 -0
- package/src/middleware.js +288 -0
- package/src/rate-limiter.js +186 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 zeesu-royalist
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,407 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 🛡️ Z-Shield
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Lightweight, zero-dependency API abuse detection, rate limiting, and security event logging toolkit for Node.js and Express backends.
|
|
4
|
+
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://nodejs.org)
|
|
7
|
+
[](package.json)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Table of Contents
|
|
12
|
+
|
|
13
|
+
- [What is Z-Shield?](#what-is-z-shield)
|
|
14
|
+
- [What Z-Shield Does](#what-z-shield-does)
|
|
15
|
+
- [What Z-Shield Does NOT Do](#what-z-shield-does-not-do)
|
|
16
|
+
- [Requirements & Installation](#requirements--installation)
|
|
17
|
+
- [Quick Start: Express Integration](#quick-start-express-integration)
|
|
18
|
+
- [Monitor Mode vs. Protect Mode](#monitor-mode-vs-protect-mode)
|
|
19
|
+
- [Configuration Reference](#configuration-reference)
|
|
20
|
+
- [Rate Limiting & HTTP Headers](#rate-limiting--http-headers)
|
|
21
|
+
- [Programmatic Block API](#programmatic-block-api)
|
|
22
|
+
- [Local Security Event Logging (.jsonl)](#local-security-event-logging-jsonl)
|
|
23
|
+
- [Z-Shield CLI](#z-shield-cli)
|
|
24
|
+
- [CLI Commands](#cli-commands)
|
|
25
|
+
- [Process-Local Architecture Notice](#process-local-architecture-notice)
|
|
26
|
+
- [Client IP & Reverse Proxy Security](#client-ip--reverse-proxy-security)
|
|
27
|
+
- [Known Limitations](#known-limitations)
|
|
28
|
+
- [Running Tests & Examples](#running-tests--examples)
|
|
29
|
+
- [Troubleshooting](#troubleshooting)
|
|
30
|
+
- [Security Disclosures](#security-disclosures)
|
|
31
|
+
- [License](#license)
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## What is Z-Shield?
|
|
36
|
+
|
|
37
|
+
**Z-Shield** is a self-contained, privacy-focused security toolkit for Node.js backends. It intercepts incoming HTTP requests, tracks request volume per IP in bounded server memory, enforces rate limits, logs security violations locally, and provides a CLI for inspecting live and historical security events.
|
|
38
|
+
|
|
39
|
+
It operates entirely locally with **zero external runtime dependencies**—no databases, no Redis clusters, no online dashboards, and no cloud telemetry required.
|
|
40
|
+
|
|
41
|
+
### What Z-Shield Does
|
|
42
|
+
- **Request Monitoring**: Tracks client requests by IP using a sliding time window.
|
|
43
|
+
- **Abuse Detection**: Detects traffic bursts exceeding your configured threshold.
|
|
44
|
+
- **Flexible Enforcement**:
|
|
45
|
+
- **Monitor Mode**: Detects violations, logs them, attaches warning headers, but lets requests through unharmed.
|
|
46
|
+
- **Protect Mode**: Enforces rate limits by rejecting offending requests with `HTTP 429 Too Many Requests` and a standard `Retry-After` header.
|
|
47
|
+
- **Temporary IP Blocking**: Supports time-based temporary IP bans with automatic expiration.
|
|
48
|
+
- **Safe Local Logging**: Writes structured security events to local JSON Lines (`.jsonl`) files with built-in log rotation and retention limits.
|
|
49
|
+
- **Log Injection Defense**: Sanitizes all untrusted input (routes, IPs, user agents) to prevent Log Injection (CWE-117) and terminal escape code exploits.
|
|
50
|
+
- **Privacy Protection**: Strictly ignores sensitive data—passwords, cookies, authorization tokens, and request bodies are never recorded (CWE-532).
|
|
51
|
+
- **DoS Memory Bounds**: Uses an LRU (Least Recently Used) cache strategy so an attacker cannot flood arbitrary IPs to exhaust server RAM.
|
|
52
|
+
- **Developer CLI**: Inspect status, view recent logs, and stream real-time events via `npx z-shield`.
|
|
53
|
+
|
|
54
|
+
### What Z-Shield Does NOT Do
|
|
55
|
+
- It is **not a full Web Application Firewall (WAF)** (it does not inspect SQL queries or deep packet payloads).
|
|
56
|
+
- It is **not a distributed rate limiter** (counters and temporary blocks are process-local to the single Node.js instance).
|
|
57
|
+
- It does **not prevent DDoS attacks** at the network/transport layer (L3/L4 volumetric attacks must be mitigated by cloud providers like Cloudflare, AWS Shield, etc.).
|
|
58
|
+
- It does **not authenticate users** or replace application login logic.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Requirements & Installation
|
|
63
|
+
|
|
64
|
+
- **Node.js**: Version `18.0.0` or higher (uses built-in `node:test`, `node:assert`, `node:fs/promises`, and `node:net`).
|
|
65
|
+
- **Express**: Version `4.x` or higher.
|
|
66
|
+
|
|
67
|
+
Install Z-Shield into your project via npm:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npm install z-shield
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
*(Note: Z-Shield has 0 external runtime dependencies).*
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Quick Start: Express Integration
|
|
78
|
+
|
|
79
|
+
Here is a minimal, complete example showing how to mount Z-Shield in an Express application:
|
|
80
|
+
|
|
81
|
+
```javascript
|
|
82
|
+
'use strict';
|
|
83
|
+
|
|
84
|
+
const express = require('express');
|
|
85
|
+
const { createShield } = require('z-shield');
|
|
86
|
+
|
|
87
|
+
const app = express();
|
|
88
|
+
|
|
89
|
+
// 1. Initialize Z-Shield with your settings
|
|
90
|
+
const shield = createShield({
|
|
91
|
+
appName: 'my-api',
|
|
92
|
+
mode: 'protect', // 'monitor' (log only) or 'protect' (enforce 429)
|
|
93
|
+
windowMs: 60 * 1000, // 1 minute window
|
|
94
|
+
maxRequests: 100, // 100 requests per minute per IP
|
|
95
|
+
excludeRoutes: ['/health']// Routes that bypass rate limiting
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// 2. Mount Z-Shield middleware as early as possible in your pipeline
|
|
99
|
+
app.use(shield.middleware);
|
|
100
|
+
|
|
101
|
+
// 3. Define your routes
|
|
102
|
+
app.get('/', (req, res) => {
|
|
103
|
+
res.json({ message: 'Hello from Z-Shield protected API!' });
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
app.get('/health', (req, res) => {
|
|
107
|
+
res.json({ status: 'healthy' });
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
app.listen(3000, () => {
|
|
111
|
+
console.log('Server running at http://localhost:3000');
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Monitor Mode vs. Protect Mode
|
|
118
|
+
|
|
119
|
+
Z-Shield provides two operational modes:
|
|
120
|
+
|
|
121
|
+
| Feature | `mode: 'monitor'` | `mode: 'protect'` |
|
|
122
|
+
| :--- | :--- | :--- |
|
|
123
|
+
| **Normal Traffic** | Passes through (`HTTP 200`) | Passes through (`HTTP 200`) |
|
|
124
|
+
| **Threshold Exceeded** | Passes through (`HTTP 200`) | Blocked (`HTTP 429 Too Many Requests`) |
|
|
125
|
+
| **Active Blocked IP** | Passes through (`HTTP 200`) | Blocked (`HTTP 429 Too Many Requests`) |
|
|
126
|
+
| **Warning Headers** | `X-Z-Shield-Suspicious: 1` | `X-Z-Shield-Suspicious: 1` |
|
|
127
|
+
| **Action Logged** | `"action": "warned"` | `"action": "blocked"` |
|
|
128
|
+
| **Best Used For** | Initial deployment, tuning limits, traffic audits | Active production defense against brute force and scraping |
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Configuration Reference
|
|
133
|
+
|
|
134
|
+
Pass an options object to `createShield(options)`. All settings are validated and frozen at startup:
|
|
135
|
+
|
|
136
|
+
```javascript
|
|
137
|
+
const shield = createShield({
|
|
138
|
+
// Unique application name (alphanumeric, dashes, underscores only)
|
|
139
|
+
appName: 'default-app',
|
|
140
|
+
|
|
141
|
+
// Operational mode: 'monitor' or 'protect'
|
|
142
|
+
mode: 'monitor',
|
|
143
|
+
|
|
144
|
+
// Duration of rate-limiting window in milliseconds (default: 1 minute)
|
|
145
|
+
windowMs: 60 * 1000,
|
|
146
|
+
|
|
147
|
+
// Maximum requests allowed per IP within windowMs
|
|
148
|
+
maxRequests: 100,
|
|
149
|
+
|
|
150
|
+
// Maximum unique client IPs tracked simultaneously in memory (DoS defense)
|
|
151
|
+
maxTrackedIps: 10000,
|
|
152
|
+
|
|
153
|
+
// Directory for JSON Lines event logs
|
|
154
|
+
logDir: path.join(process.cwd(), '.z-shield-logs'),
|
|
155
|
+
|
|
156
|
+
// Filename for active event log
|
|
157
|
+
logFilename: 'events.jsonl',
|
|
158
|
+
|
|
159
|
+
// Max size in bytes before rotating log file (default: 5MB)
|
|
160
|
+
maxLogSizeBytes: 5 * 1024 * 1024,
|
|
161
|
+
|
|
162
|
+
// Number of rotated log files to retain
|
|
163
|
+
maxLogFiles: 5,
|
|
164
|
+
|
|
165
|
+
// Default duration for temporary blocks (default: 15 minutes)
|
|
166
|
+
blockDurationMs: 15 * 60 * 1000,
|
|
167
|
+
|
|
168
|
+
// Max blocked IPs to keep in memory simultaneously
|
|
169
|
+
maxBlockedIps: 5000,
|
|
170
|
+
|
|
171
|
+
// Automatically place IP on temporary block list when rate limit is exceeded
|
|
172
|
+
autoBlock: false,
|
|
173
|
+
|
|
174
|
+
// Whether to trust reverse-proxy headers (e.g. X-Forwarded-For)
|
|
175
|
+
// WARNING: Set to true only if behind a verified reverse proxy
|
|
176
|
+
trustProxy: false,
|
|
177
|
+
|
|
178
|
+
// Array of route prefixes that bypass tracking
|
|
179
|
+
excludeRoutes: ['/health', '/favicon.ico'],
|
|
180
|
+
|
|
181
|
+
// Optional custom error callback for failed log writes: (err, event) => void
|
|
182
|
+
onLogError: null
|
|
183
|
+
});
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Rate Limiting & HTTP Headers
|
|
189
|
+
|
|
190
|
+
Every request processed by Z-Shield receives informative, RFC-aligned HTTP response headers:
|
|
191
|
+
|
|
192
|
+
| Header | Description | Example |
|
|
193
|
+
| :--- | :--- | :--- |
|
|
194
|
+
| `X-Z-Shield-Protected` | Confirms Z-Shield middleware processed the request | `1` |
|
|
195
|
+
| `X-Z-Shield-Mode` | Active operational mode | `protect` or `monitor` |
|
|
196
|
+
| `X-RateLimit-Limit` | Maximum allowed requests per window | `100` |
|
|
197
|
+
| `X-RateLimit-Remaining` | Remaining requests allowed in current window | `42` |
|
|
198
|
+
| `X-RateLimit-Reset` | Unix timestamp (seconds) when the window resets | `1792412398` |
|
|
199
|
+
| `X-Z-Shield-Suspicious` | Set to `1` if threshold was exceeded or IP is flagged | `1` |
|
|
200
|
+
| `X-Z-Shield-Blocked` | Set to `1` if request was stopped due to an active block | `1` |
|
|
201
|
+
| `Retry-After` | Seconds client must wait before retrying (sent on 429) | `30` |
|
|
202
|
+
|
|
203
|
+
### Blocked Response Body (HTTP 429)
|
|
204
|
+
When a request is blocked in `protect` mode, Z-Shield immediately responds with status `429` and terminates processing:
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"error": "Too Many Requests",
|
|
209
|
+
"message": "Request threshold exceeded. Please try again later.",
|
|
210
|
+
"retryAfter": 30
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Programmatic Block API
|
|
217
|
+
|
|
218
|
+
You can programmatically manage blocks in your Node.js code via the `shield` instance. No unauthenticated network endpoints are created:
|
|
219
|
+
|
|
220
|
+
```javascript
|
|
221
|
+
// Temporarily block an IP (supports milliseconds or strings like '30s', '10m', '1h', '2d')
|
|
222
|
+
shield.block('198.51.100.1', '10m', 'Repeated failed login attempts');
|
|
223
|
+
|
|
224
|
+
// Manually unblock an IP
|
|
225
|
+
shield.unblock('198.51.100.1');
|
|
226
|
+
|
|
227
|
+
// Check if an IP is currently blocked (returns boolean)
|
|
228
|
+
const isBlocked = shield.isBlocked('198.51.100.1');
|
|
229
|
+
|
|
230
|
+
// Retrieve block details (or null if not blocked)
|
|
231
|
+
const info = shield.getBlockInfo('198.51.100.1');
|
|
232
|
+
// Returns: { ip: '198.51.100.1', blockedAt: ..., expiresAt: ..., remainingMs: ..., reason: '...' }
|
|
233
|
+
|
|
234
|
+
// List all active blocks
|
|
235
|
+
const activeBlocks = shield.listBlocks();
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Local Security Event Logging (.jsonl)
|
|
241
|
+
|
|
242
|
+
Z-Shield automatically logs security events (rate limit breaches, blocks, warnings, and manual actions) to a local JSON Lines file:
|
|
243
|
+
|
|
244
|
+
**Default path**: `.z-shield-logs/events.jsonl`
|
|
245
|
+
|
|
246
|
+
### Example Log Record:
|
|
247
|
+
```json
|
|
248
|
+
{
|
|
249
|
+
"timestamp": "2026-10-19T12:28:23.726Z",
|
|
250
|
+
"appName": "my-api",
|
|
251
|
+
"type": "rate_limit",
|
|
252
|
+
"severity": "warning",
|
|
253
|
+
"ip": "198.51.100.1",
|
|
254
|
+
"method": "POST",
|
|
255
|
+
"route": "/api/login",
|
|
256
|
+
"reason": "Request threshold exceeded (6/5 in 30s)",
|
|
257
|
+
"action": "blocked"
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Log Rotation & Retention
|
|
262
|
+
- When `events.jsonl` reaches `maxLogSizeBytes` (default: 5MB), Z-Shield rotates it to `events.1.jsonl`.
|
|
263
|
+
- Up to `maxLogFiles` (default: 5) historical files are preserved. Older files beyond the retention limit are automatically deleted.
|
|
264
|
+
- Log writes are executed in a sequential non-blocking queue, preventing file corruption under heavy concurrency.
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Z-Shield CLI
|
|
269
|
+
|
|
270
|
+
Z-Shield provides a built-in terminal CLI to inspect and monitor security events.
|
|
271
|
+
|
|
272
|
+
### CLI Commands
|
|
273
|
+
|
|
274
|
+
Run these commands in a separate terminal:
|
|
275
|
+
|
|
276
|
+
#### 1. View Security Status & Top Offenders
|
|
277
|
+
```bash
|
|
278
|
+
npx z-shield status
|
|
279
|
+
```
|
|
280
|
+
Shows total events, action counts (`BLOCKED`, `WARNED`), top targeted routes, and top offending IP addresses.
|
|
281
|
+
|
|
282
|
+
#### 2. View Recent Event Logs
|
|
283
|
+
```bash
|
|
284
|
+
# View last 20 events (default)
|
|
285
|
+
npx z-shield logs
|
|
286
|
+
|
|
287
|
+
# View last 50 events
|
|
288
|
+
npx z-shield logs --limit 50
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
#### 3. Real-Time Security Event Stream (`monitor`)
|
|
292
|
+
```bash
|
|
293
|
+
npx z-shield monitor
|
|
294
|
+
```
|
|
295
|
+
Tails the `.jsonl` log file and streams new security events in real time. Press `Ctrl+C` to exit cleanly.
|
|
296
|
+
|
|
297
|
+
#### 4. Block / Unblock Commands
|
|
298
|
+
```bash
|
|
299
|
+
npx z-shield block 198.51.100.1 --duration 10m
|
|
300
|
+
npx z-shield unblock 198.51.100.1
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Process-Local Architecture Notice
|
|
304
|
+
Z-Shield stores active IP counters and temporary blocks **in server memory (RAM)** inside your Express application process.
|
|
305
|
+
|
|
306
|
+
Because the CLI runs in an independent Node.js process, it cannot reach into your Express application's memory heap to alter active blocks. When you execute `npx z-shield block`, the CLI:
|
|
307
|
+
1. Validates the IP and duration.
|
|
308
|
+
2. Writes an audit entry to `.z-shield-logs/events.jsonl`.
|
|
309
|
+
3. Displays the exact JavaScript snippet to invoke inside your Express code (`shield.block(...)`).
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Client IP & Reverse Proxy Security
|
|
314
|
+
|
|
315
|
+
### The Spoofing Risk
|
|
316
|
+
HTTP headers like `X-Forwarded-For` can be trivially forged by any client:
|
|
317
|
+
```bash
|
|
318
|
+
curl -H "X-Forwarded-For: 1.1.1.1" https://your-api.com
|
|
319
|
+
```
|
|
320
|
+
If your application blindly trusts `X-Forwarded-For`, an attacker could rotate fake IP headers on every request to bypass all rate limits and temporary blocks.
|
|
321
|
+
|
|
322
|
+
### Z-Shield Anti-Spoofing Rules
|
|
323
|
+
1. **`trustProxy: false` (Default)**: Z-Shield **completely ignores** `X-Forwarded-For` and inspects the raw TCP socket connection IP (`req.socket.remoteAddress`).
|
|
324
|
+
2. **`trustProxy: true`**: Z-Shield relies on Express's validated `req.ip`. You **must** configure Express's proxy policy correctly:
|
|
325
|
+
|
|
326
|
+
```javascript
|
|
327
|
+
const app = express();
|
|
328
|
+
|
|
329
|
+
// Configure Express trust proxy for your specific reverse proxy setup
|
|
330
|
+
// See Express documentation: http://expressjs.com/en/guide/behind-proxies.html
|
|
331
|
+
app.set('trust proxy', 'loopback'); // or specific IP of your Nginx / AWS ALB
|
|
332
|
+
|
|
333
|
+
const shield = createShield({
|
|
334
|
+
trustProxy: true // Safe only because Express trust proxy is configured above
|
|
335
|
+
});
|
|
336
|
+
app.use(shield.middleware);
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## Known Limitations
|
|
342
|
+
|
|
343
|
+
We believe in full engineering transparency:
|
|
344
|
+
|
|
345
|
+
1. **Process-Local Memory**:
|
|
346
|
+
- In this release, counters and active blocks reside in the Node.js process heap.
|
|
347
|
+
- If you run multiple server instances or multiple Node.js cluster workers, counters are not shared across processes. (A distributed Redis adapter is planned for a future release).
|
|
348
|
+
2. **Restarts Reset Memory**:
|
|
349
|
+
- When your Node.js application process restarts or crashes, in-memory counters and temporary blocks reset. (Historical event logs in `.z-shield-logs/events.jsonl` persist on disk).
|
|
350
|
+
3. **Fixed-Window Boundary Burst**:
|
|
351
|
+
- Z-Shield uses a fixed window per IP. If an IP sends 100 requests right before the window expires, and 100 requests immediately after it resets, 200 requests pass in a short span without exceeding either window limit.
|
|
352
|
+
4. **Ephemeral Hosting Filesystems**:
|
|
353
|
+
- On serverless platforms or ephemeral container dynos (such as basic Heroku or AWS Lambda), local `.z-shield-logs` files will be reset upon container termination. Persistent volume mounts are recommended for persistent auditing.
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## Running Tests & Examples
|
|
358
|
+
|
|
359
|
+
### Automated Test Suite
|
|
360
|
+
Z-Shield includes comprehensive unit and integration tests using Node.js's built-in `node:test` and `node:assert`:
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
npm test
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Running the Demo Application
|
|
367
|
+
Start the runnable Express demo:
|
|
368
|
+
|
|
369
|
+
```bash
|
|
370
|
+
npm start
|
|
371
|
+
```
|
|
372
|
+
*(Runs at `http://localhost:3000` with rate limit set to 5 requests per 30s for easy testing).*
|
|
373
|
+
|
|
374
|
+
Test hitting the limit in a second terminal:
|
|
375
|
+
```bash
|
|
376
|
+
for i in {1..6}; do curl -s -i http://localhost:3000/ | head -n 8; echo "---"; done
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
To run the demo in monitor mode instead:
|
|
380
|
+
```bash
|
|
381
|
+
SHIELD_MODE=monitor npm start
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
## Troubleshooting
|
|
387
|
+
|
|
388
|
+
### Q: Why do all requests seem to come from `127.0.0.1`?
|
|
389
|
+
**A**: When testing locally, `127.0.0.1` is your loopback address. In production behind a reverse proxy (like Nginx), make sure you configured `app.set('trust proxy', ...)` in Express and set `trustProxy: true` in Z-Shield.
|
|
390
|
+
|
|
391
|
+
### Q: Why did an IP get blocked in one worker but allowed in another?
|
|
392
|
+
**A**: Node.js cluster workers run in separate processes with isolated memory heaps. Each worker maintains its own in-memory counter.
|
|
393
|
+
|
|
394
|
+
### Q: Why did `npx z-shield status` say "No log file found yet"?
|
|
395
|
+
**A**: The `.z-shield-logs/events.jsonl` file is created automatically when the first security violation occurs. Start your server and trigger a threshold violation to generate log data.
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
## Security Disclosures
|
|
400
|
+
|
|
401
|
+
For vulnerability disclosures and reporting procedures, please refer to [SECURITY.md](SECURITY.md).
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## License
|
|
406
|
+
|
|
407
|
+
[MIT](LICENSE) © 2026 zeesu-royalist
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Reporting Security Vulnerabilities
|
|
4
|
+
|
|
5
|
+
We take the security of **Z-Shield** seriously. If you discover a security vulnerability, please disclose it responsibly so we can investigate and address it before public disclosure.
|
|
6
|
+
|
|
7
|
+
> **Important**: Please do **NOT** open public GitHub issues, pull requests, or discussions for undisclosed security vulnerabilities.
|
|
8
|
+
|
|
9
|
+
### How to Report Privately
|
|
10
|
+
Please submit vulnerability reports privately through one of the following channels:
|
|
11
|
+
1. **GitHub Private Vulnerability Reporting**: Use the "Report a vulnerability" button under the **Security** tab of the Z-Shield repository (recommended).
|
|
12
|
+
2. **Designated Maintainer Contact**: `md.jishan.dev@gmail.com`
|
|
13
|
+
|
|
14
|
+
You will receive an acknowledgment of your report within 48 hours, followed by regular status updates as we evaluate and remediate the issue.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
### What to Include in a Report
|
|
19
|
+
To help us triage and resolve the issue quickly, please provide:
|
|
20
|
+
- **Description**: A clear summary of the vulnerability and its potential impact.
|
|
21
|
+
- **Affected Versions**: The version of Z-Shield where the vulnerability was observed.
|
|
22
|
+
- **Reproduction Steps**: A minimal, reproducible example (e.g., sample code, `curl` commands, or a small script demonstrating the flaw).
|
|
23
|
+
- **Proof of Concept**: Details on how the exploit is triggered.
|
|
24
|
+
- **Remediation Ideas**: Any proposed patches or mitigations, if known.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
### Scope and Vulnerability Types
|
|
29
|
+
|
|
30
|
+
#### Vulnerabilities In Scope:
|
|
31
|
+
- **Log Injection / CRLF Injection (CWE-117)**: Any condition that allows unescaped newlines or control characters to forge log entries in `.jsonl` files.
|
|
32
|
+
- **Memory Exhaustion / DoS (CWE-400)**: Any scenario where unauthenticated incoming requests can bypass LRU bounds and cause an unbounded heap leak.
|
|
33
|
+
- **IP Spoofing / Header Smuggling**: Flaws in client IP resolution that allow bypassing rate limits or blocks under supported Express proxy configurations.
|
|
34
|
+
- **Terminal Injection**: Scenarios where untrusted log data prints executable ANSI escape sequences to developer terminals.
|
|
35
|
+
- **Information Disclosure (CWE-532)**: Accidental logging of request bodies, passwords, cookies, or authorization headers.
|
|
36
|
+
|
|
37
|
+
#### Out of Scope (Known Documented Limitations):
|
|
38
|
+
- **Cross-Process / Multi-Worker State Sharing**: In this release, counters and temporary blocks are intentionally process-local in memory. Running multiple Node.js cluster workers or server instances without a centralized distributed adapter (like Redis) will result in independent counters per process. This is a documented architectural choice, not a vulnerability.
|
|
39
|
+
- **Process Restarts**: In-memory counters and blocks intentionally reset when the Node.js process terminates.
|
|
40
|
+
- **Misconfigured Proxies**: If the host application configures Express `app.set('trust proxy', true)` while sitting directly on the public internet without a reverse proxy, client-controlled `X-Forwarded-For` headers will be trusted. This is a configuration mistake in the host application.
|
|
41
|
+
- **Ephemeral Filesystem Data Loss**: On platforms with ephemeral disk storage (e.g. serverless containers), local `.jsonl` files reset when containers cycle.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
### Security Best Practices for Users
|
|
46
|
+
1. **Keep Node.js Updated**: Run Z-Shield on active Node.js LTS releases.
|
|
47
|
+
2. **Configure Proxies Safely**: Only set `trustProxy: true` if your app runs behind a properly configured reverse proxy (such as Nginx, Cloudflare, or AWS ALB) that strips spoofed headers.
|
|
48
|
+
3. **Restrict Log Directory Permissions**: Ensure the `.z-shield-logs` directory has restrictive read/write permissions on the host system.
|
package/package.json
CHANGED
|
@@ -1,6 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "z-shield",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "API abuse detection, rate limiting, and temporary IP blocking middleware for Node.js and Express",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"z-shield": "src/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "node --test test/*.test.js",
|
|
11
|
+
"start": "node examples/express-app.js"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/zeesu-royalist/z-shield-npm-package.git"
|
|
16
|
+
},
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/zeesu-royalist/z-shield-npm-package/issues"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://github.com/zeesu-royalist/z-shield-npm-package#readme",
|
|
21
|
+
"keywords": [
|
|
22
|
+
"security",
|
|
23
|
+
"rate-limit",
|
|
24
|
+
"abuse-detection",
|
|
25
|
+
"express",
|
|
26
|
+
"middleware",
|
|
27
|
+
"api-protection"
|
|
28
|
+
],
|
|
29
|
+
"author": "zeesu-royalist (https://zeesu-royalist.vercel.app)",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"files": [
|
|
32
|
+
"src",
|
|
33
|
+
"README.md",
|
|
34
|
+
"LICENSE",
|
|
35
|
+
"SECURITY.md"
|
|
36
|
+
],
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"express": "^4.21.2"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=18.0.0"
|
|
42
|
+
}
|
|
43
|
+
}
|