Fail-open internals
Internal errors are caught and logged. A detector issue never becomes an outage for your users.
A small, auditable Express middleware for detecting high-signal attacks at runtime. Inspect requests, score evidence, and choose whether to allow, warn, throttle, or block.
01 / Quick start
Drop it before your routes. Sensible defaults cover common attack patterns immediately, and every decision remains visible to your app.
import express from "express";
import { securityWatch } from "securitywatch";
const app = express();
app.use(securityWatch());
app.listen(3000);02 / The model
Each detector returns a numeric score instead of a binary yes/no. Scores are summed, multiplied by route sensitivity, and compared against thresholds.
Request passes normally
Passes with threat info attached
429 response
403 response
A single weak signal will not lock out a real user. Several signals together will. Scores also accumulate per IP with automatic decay, so repeat offenders get blocked faster while normal users stay unaffected.
03 / Detection rules
Built-in rules target high-signal patterns across payloads, paths, headers, and request behavior.
| Pattern | Score | Example |
|---|---|---|
| Tautology | +5 | ' OR 1=1 |
| UNION SELECT | +5 | 1 UNION SELECT * FROM users |
| Stacked queries | +6 | 1; DROP TABLE users |
| Comment bypass + keyword | +4 | -- SELECT * FROM |
| Encoded injection | +4 | CHAR(0x75) |
| Time-based blind | +5 | SLEEP(5) |
| NoSQL operators | +4 | {"$gt": ""} |
| Command execution | +6 | xp_cmdshell, cmd.exe |
| Schema manipulation | +6 | DROP TABLE, ALTER TABLE |
| Mass data export | +5 | INTO OUTFILE, mysqldump |
| Pattern | Score | Example |
|---|---|---|
| Script tag | +6 | <script>alert(1)</script> |
| javascript: protocol | +5 | javascript:alert(1) |
| Event handlers (20+ types) | +4 | onerror=, onfocusin= |
| Dangerous tags | +4 | <iframe>, <svg>, <object> |
| Data URI | +4 | data:text/html,... |
| eval / Function | +3 | eval(...) |
| Template injection | +3 | ${...} |
| Pattern | Score | Example |
|---|---|---|
| Sensitive path probing | +5 | GET /.env |
| Directory traversal | +6 | ../../etc/passwd |
| Endpoint scanning | +5 | crawling unknown paths |
| Suspicious file extensions | +4 | .sql, .bak, .env |
| Unusual methods on auth routes | +3 | DELETE /login |
04 / Configuration
Tune thresholds, route sensitivity, rate limits, brute-force protection, and alert hooks without changing your application architecture.
app.use(securityWatch({
bruteForce: {
maxAttempts: 5,
windowMs: 5 * 60_000,
blockDurationMs: 15 * 60_000,
authRoutes: ["/login", "/auth"],
},
rateLimit: {
windowMs: 60_000,
maxRequests: 100,
routes: { "/login": 5, "/api": 60 },
},
routeSensitivity: {
"/admin": "critical",
"/login": "high",
"/search": "low",
},
thresholds: { warn: 5, throttle: 10, block: 15 },
whitelist: ["127.0.0.1"],
}));05 / API surface
Every detector is exported independently, so you can use one signal in a custom flow or compose your own middleware.
import { detectSQLInjection, detectXSS } from "securitywatch";
detectSQLInjection("' OR 1=1--");
// { triggered: true, score: 5,
// rule: "sql-injection",
// reason: "SQL injection: tautology attack" }06 / Production notes
Internal errors are caught and logged. A detector issue never becomes an outage for your users.
Tracking is capped at 10K IPs and 100 routes per IP. Inputs are truncated before scanning.
X-Forwarded-For is ignored by default. Enable trustProxy only behind a proxy you control.
Start with a safer default
One dependency. No dashboard. No external service. Just a clearer signal at the edge of your app.
npm install securitywatch