EDR-level Web Application Firewall for Node.js
Context-aware security engine with Stateful Session Analysis & Behavioral Fingerprinting
β οΈ DISCLAIMERThis project is provided "as-is" for educational and research purposes. It requires adaptation and tuning for any specific deployment. The authors accept no responsibility for vulnerabilities, false positives, or security incidents in applications that use this middleware. Always combine ShieldWall with other security layers β it is not a silver bullet.
ShieldWall takes a layered approach instead of trying to enumerate every known attack signature:
HTTP Request (Gateway)
β
ββ 1. TLS Interception JA3/JA4 extraction, Client Random entropy, GREASE detection
β
Request Payload (Engine)
β
ββ 2. Multi-layer Decoder URL / HTML / Unicode / Base64 normalization
ββ 3. Anomaly Scoring N-Gram deviation, Shannon entropy, SSTI, Prototype Pollution
ββ 4. Adaptive Baselines Per-parameter profiling (EWMA length/type tracking)
ββ 5. Session EDR (Stateful) Request Lineage (Graph), BOLA/IDOR tracking
ββ 6. Sequence Analysis Mathematical scraping & ID enumeration detection
ββ 7. Honeypot Traps Invisible forms, fake endpoints, bot detection
ββ 8. .shield Rule Engine YARA-inspired DSL for custom logic
ββ 9. Rate Limiter Sliding window per-IP & Brute-force guard
ββ 10. Cross-Module Boosting Non-linear risk aggregation (Bot + Payload)
ββ 11. Feedback Loop Backend Timing (Blind SQLi) & Exfiltration detection
ββ 12. Security Headers CSP, HSTS, X-Frame-Options, Permissions-Policy
The key insight: instead of hardcoding thousands of exploit payloads, ShieldWall asks "does this request look normal?" The anomaly scorer assigns a suspicion score based on behavioral signals (encoding layers, character entropy, nesting depth, mixed encoding schemes), while baseline patterns and .shield rules catch the most obvious structural attack shapes.
This makes it database-agnostic and adaptive β it works against SQL, NoSQL, LDAP, GraphQL, or any other injection target.
ShieldWall has strict separation between layers. Each makes promises about what it does and does not do, ensuring predictable, non-destructive behavior:
| Layer | Role | Does NOT |
|---|---|---|
| Decoder | Normalizes encoding (URL, HTML, Unicode, Base64). Produces canonical request representation | Make security decisions. Mutate original request. Call network |
| Feature Extractor | Calculates entropy, encoding depth, char distribution | Block or allow anything. Persist state |
| Detectors (modules) | Match patterns, score signals, detect anomalies | Write to disk. Make network calls |
| Scoring Engine | Aggregates detector outputs into risk score | Enforce policy (block/allow) |
| Decision Engine | Applies policy (block/detect/log) based on score + severity | Normalize input. Score signals |
| Auto-Rule Generator | Creates candidate signatures from zero-day anomalies | Promote rules without TTL. Override existing rules |
- Decoding is bounded (
MAX_DECODE_DEPTH = 5). - No network calls in the hot path.
- No mutation of the original
reqobject. - Deterministic output for identical input (no randomness).
- Auto-generated rules expire after 7 days (must be manually promoted).
- Feedback loop adapts signal weights but never drops below 10% base weight, preventing self-muting.
npm install shieldwallconst express = require('express');
const shieldwall = require('shieldwall');
const app = express();
app.use(express.json());
app.use(shieldwall({
mode: 'block', // 'block' or 'detect' (log only)
dashboard: { port: 9090 },
rateLimit: { max: 100 },
bruteForce: { maxAttempts: 5 },
}));
app.get('/', (req, res) => {
res.json({ message: 'Protected by ShieldWall π‘οΈ' });
});
app.listen(3000);Write custom detection rules in a YARA-inspired DSL:
rule my_detection : tag {
meta:
author = "You"
description = "What this catches and why"
severity = "critical"
target:
$url = request.url
$body = request.body
strings:
$pattern = /suspicious_regex/i
condition:
$pattern in $url or $pattern in $body
}
| Target | Description |
|---|---|
request.url |
Full decoded URL |
request.body |
Request body |
request.query |
Query string parameters |
request.headers |
All headers |
request.cookies |
Cookie values |
request.useragent |
User-Agent string |
request.raw_url |
URL before decoding (for evasion detection) |
request.session / request.sessionid |
Session identifier |
request.timestamp / request.time |
Request timestamp |
request.geoip / request.geo |
GeoIP data (country, city, ASN) |
request.fingerprint / request.fp |
Browser/device fingerprint |
request.rate |
Rate limit counter data |
and, or, not, in (target-scoped match), any of them, all of them, ( ) grouping.
Rules can be loaded from files, directories, or inline strings β see examples.
| File | Protection |
|---|---|
sqli.shield |
SQL and NoSQL injection patterns |
xss.shield |
Cross-site scripting attacks |
traversal.shield |
Path traversal and LFI/RFI |
cmdi.shield |
Command injection attacks |
protocol.shield |
HTTP smuggling, SSRF, CRLF injection |
scanner.shield |
Known security scanner detection |
graphql.shield |
GraphQL query depth bombing and introspection |
jwt.shield |
JWT algorithm confusion and key injection |
deserialization.shield |
Java/PHP/Node.js/Python deserialization |
cors.shield |
CORS misconfiguration abuse |
file_upload.shield |
Dangerous file upload patterns |
dos_protection.shield |
L7 DDoS - Slowloris, header swelling, parameter floods |
api_security.shield |
IDOR/BOLA, mass assignment, anomalous Content-Type |
proto_pollution.shield |
Node.js prototype pollution attacks |
obfuscation_evasion.shield |
Double Base64, hex encoding, Unicode homoglyphs |
business_logic.shield |
Form speed, cart manipulation, scraping patterns |
security_misconfig.shield |
Debug endpoints, config files, backup access |
| Module | Approach |
|---|---|
| Anomaly Scoring | Behavioral heuristics β encoding layers, char density, nesting depth, mixed schemes, entropy analysis, parameter pollution, raw byte injection, payload inflation, header integrity |
| Honeypot | Invisible HTML traps, fake admin panels, fake APIs β flags anything that interacts |
| Injection | Structural patterns (context breaks + keywords) β database-agnostic |
| XSS | HTML execution shapes (tags, handlers, protocol, DOM sinks) |
| Path Traversal | Decoded traversal + encoding evasion detection on raw URL |
| Command Injection | Shell metacharacter + command name structural pair |
| Scanner Detection | User-Agent fingerprints and out-of-band callback domains |
| Protocol Abuse | HTTP smuggling, SSRF, CRLF, host header poisoning |
| Rate Limiter | Sliding window per-IP with auto-blocking |
| Brute-Force Guard | Progressive backoff on sensitive endpoints |
| Security Headers | CSP, HSTS, Permissions-Policy, etc. (helmet.js alternative) |
| Bot Detection | Headless browser detection, automation tools, behavioral analysis |
| Session Anomaly | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // β ShieldWall Session EDR (Stateful) β | |
| // β β | |
| // β Provides high-level context awareness similar to Endpoint Detection β | |
| // β and Response (EDR) systems. Tracks sessions across requests to detect β | |
| // β logical bypasses, lateral movement, and identity theft. β | |
| // β β | |
| // β Core Capabilities: β | |
| // β ββ Request Lineage: Validates logical navigation flow graphs. β | |
| // β ββ BOLA/IDOR Detection: Tracks resource ID access patterns. β | |
| // β ββ Context Drift: Monitors IP/TLS identity shifts mid-session. β | |
| // β ββ Velocity Control: Detects "Impossible Human" interaction speeds. β | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| API Abuse | GraphQL complexity analysis, REST enumeration, batch attack detection |
| DDoS Protection | L7 flood detection - Slowloris, oversized headers, connection floods |
All thresholds are empirically tuned against a mix of legitimate web traffic and known attack corpora (SQLi, XSS, encoded payloads, PE/ELF uploads). Reference scores for common payloads:
| Payload type | Typical score | Level |
|---|---|---|
Normal GET /api/users |
0 β 3 | none |
| GraphQL introspection | 4 β 8 | none/low |
| JWT in Authorization | 2 β 5 | none |
' OR 1=1 -- |
12 β 18 | medium/high |
| UNION SELECT (encoded) | 22 β 35 | high/critical |
<script>alert(1)</script> |
14 β 20 | high |
| Multi-layer encoded payload | 20 β 40+ | critical |
Score threshold (15) β lowest score at which known attacks reliably trigger.
Critical threshold (30) β requires β₯3 independent high-weight signals; extremely unlikely for legitimate traffic.
Entropy 5.5 β sits above normal URL-encoded values (β4.5β5.2) but below pure base64/encrypted data (β5.8β6.0).
Known false-positive sources (JWTs, GraphQL introspection, hex hashes, versioned REST paths) are automatically suppressed.
ShieldWall automatically injects invisible HTML traps into your pages:
- Hidden forms that humans can't see but bots auto-fill
- Fake links to
/admin-panel,/.env,/.git/config - Fake API endpoints like
/api/internal/debug
Any interaction with these traps immediately flags the client as a bot.
Real-time monitoring at http://localhost:9090:
- Live attack feed with severity indicators
- Why each request was blocked (human-readable explanations)
- Severity breakdown, top attack types, top attacker IPs
- WebSocket-powered β updates instantly
shieldwall({
mode: 'block', // 'block' | 'detect'
logLevel: 'info', // 'error' | 'warn' | 'info' | 'debug'
jsonLogs: false, // structured JSON output
rulesDir: './rules', // .shield files directory
customRules: '...', // inline .shield string
customRulesFiles: [], // additional .shield file paths
blockStatusCode: 403,
blockMessage: null, // string or function(matches)
trustProxy: false,
excludePaths: ['/health'],
excludeIPs: ['127.0.0.1'],
modules: { anomaly: true, honeypot: true, sqli: true, xss: true, pathTraversal: true, commandInjection: true, botDetection: true, sessionAnomaly: true, apiAbuse: true },
rateLimit: { windowMs: 60000, max: 100 },
bruteForce: { maxAttempts: 5, sensitivePaths: ['/login'] },
dashboard: { port: 9090 },
headers: { hsts: { maxAge: 31536000 } },
honeypot: true, // inject HTML traps into responses
reporting: {
enabled: true,
reportsDir: './reports',
maxStoredReports: 12,
},
});const waf = shieldwall({ ... });
waf.on('threat', (event) => {
// event.matches β what triggered
// event.request β IP, method, URL
// send to Slack, Discord, webhook, SIEM...
});
waf.on('report', ({ type, report, filepath }) => {
// type: '14d' | 'monthly'
// report β full report object with trends, ROI, persistent attackers
// filepath β path to saved JSON file
});
waf.getStats(); // request/block/threat counters
waf.getReport(14); // generate report for last 14 days
waf.getStoredReports(); // get all stored reports
waf.reloadRules(); // hot-reload .shield filesShieldWall generates reports automatically:
- Every 14 days β summary report with key statistics
- Monthly β detailed report with trends, ROI metrics, vector shift analysis, and persistent attacker tracking
Reports are saved to reports/ and include:
- Attack summary by severity and category
- Top attacked endpoints with protection recommendations
- Attack dynamics (comparison with previous period)
- New attack patterns detection
- Geographic distribution
- ROI metrics (traffic saved, CPU time saved, cost estimate)
- Vector shift analysis (e.g., cmdi β api-abuse migration)
- Persistent attacker identification (IP reconnaissance tracking)
- SVG timeline charts
Every blocked request produces a structured log explaining:
[SHIELDWALL] π΄ BLOCKED | anomaly_detection [critical] | 192.168.1.50 POST /api/data
ββ Why: Anomaly score 28/30: multi_layer_encoding, unusual_char_density, comment_syntax
ββ Evidence: [multi_layer_encoding] 3 layers of URL encoding β likely evasion attempt
JSON mode (jsonLogs: true) outputs machine-parseable entries for SIEM integration.
MIT β see LICENSE
Built for the security research community.
This is a tool, not a product β tune it for your environment.