@anomira/node-sdk
v0.1.7
Published
Anomira Node.js SDK — drop-in API security monitoring for Express and Fastify
Maintainers
Readme
@anomira/node-sdk
Drop-in API security monitoring for Node.js. Detect brute force, credential stuffing, account takeover, data scraping, path traversal, XSS, geo-velocity attacks, and more — in real time.
Install
npm install @anomira/node-sdkQuick Start
import { Anomira } from "@anomira/node-sdk";
const sentinel = new Anomira({
apiKey: process.env.SENTINEL_API_KEY,
appId: process.env.SENTINEL_APP_ID,
ingestUrl: process.env.SENTINEL_INGEST_URL,
debug: true,
});Express
import express from "express";
import { Anomira } from "@anomira/node-sdk";
const app = express();
const sentinel = new Anomira({
apiKey: process.env.SENTINEL_API_KEY,
appId: process.env.SENTINEL_APP_ID,
ingestUrl: process.env.SENTINEL_INGEST_URL,
debug: true,
captureConsole: true, // forwards console.log/warn/error to Logs dashboard
service: "my-api",
detect: {
bruteForce: true,
rateAbuse: true,
pathTraversal: true,
xss: true,
scanDetection: true,
geoVelocity: true,
},
});
app.use(express.json());
app.use(sentinel.express()); // auto-instruments all routes
app.listen(3000);Fastify
import Fastify from "fastify";
import { Anomira } from "@anomira/node-sdk";
const app = Fastify();
const sentinel = new Anomira({
apiKey: process.env.SENTINEL_API_KEY,
appId: process.env.SENTINEL_APP_ID,
ingestUrl: process.env.SENTINEL_INGEST_URL,
});
await app.register(sentinel.fastify());
app.listen({ port: 3000 });Manual Event Tracking
// Track a failed OTP attempt
sentinel.track("auth.otp.failed", {
ip: req.ip,
userId: req.body.phone,
meta: { endpoint: "/api/verify-otp" },
});
// Track a login and run geo-velocity check automatically
await sentinel.trackLogin({ ip: req.ip, userId: user.id });
// Track phone-based auth (SIM swap detection)
sentinel.trackPhoneAuth({ ip: req.ip, userId: user.id, phone: user.phone });Structured Logging
sentinel.log("info", "User registered", { userId: user.id });
sentinel.log("warn", "Slow DB query", { queryMs: 1240 });
sentinel.log("error", "Payment failed", { reason: err.message });Blocklist & Firewall
The SDK syncs your blocklist and firewall rules from the dashboard every 60 seconds. Check them in your own middleware:
if (sentinel.isBlocked(req.ip)) {
return res.status(403).json({ error: "Forbidden" });
}
const match = sentinel.matchFirewallRule({
url: req.url,
body: req.body,
headers: req.headers,
ip: req.ip,
});
if (match?.rule.action === "block") {
return res.status(403).json({ error: "Blocked by firewall rule" });
}Shadow Endpoint Detection
Register your known API routes on startup so Anomira can flag any undeclared endpoint that appears in live traffic. Endpoints that receive requests but were never declared show up in the API Surface Map as shadow endpoints.
// Call once after your routes are registered
await sentinel.declareEndpoints([
{ method: "POST", path: "/api/auth/login", auth: false },
{ method: "POST", path: "/api/auth/register", auth: false },
{ method: "GET", path: "/api/users/:id", auth: true },
{ method: "GET", path: "/api/orders", auth: true },
{ method: "POST", path: "/api/orders", auth: true },
{ method: "GET", path: "/api/health", auth: false },
]);Express-style :param segments are normalized automatically — /users/:id and /users/:userId both map to /users/{id} to match discovered traffic.
Use auth: false for public endpoints. Authenticated endpoints default to auth: true.
Shadow detection from declared endpoints only activates once your org has registered at least one endpoint, so it won't produce noise on fresh deployments before you call this method.
Secret Scanner CLI
Scan your codebase for hardcoded secrets, API keys, BVN/NIN numbers, and PII before they reach production.
Uses three detection layers:
- secretlint — 50+ service-specific rules (AWS, GCP, GitHub, Stripe, Slack, Twilio, SendGrid, PostgreSQL connection strings, and more)
- Custom patterns — Nigerian PII (BVN/NIN), card PANs, phone numbers
- Entropy analysis (
--strict) — catches unknown high-entropy secrets with no known prefix, using Shannon entropy scoring
Run without installing:
npx @anomira/node-sdk scan ./srcIf @anomira/node-sdk is already installed in your project:
npx anomira scan ./srcOptions:
npx @anomira/node-sdk scan ./src # scan a directory
npx @anomira/node-sdk scan . # scan entire project
npx @anomira/node-sdk scan ./src --strict # enable entropy analysis (catches unknown secrets)
npx @anomira/node-sdk scan ./src --json # machine-readable JSON output for CI
npx @anomira/node-sdk scan ./src --quiet # only print violations, no headerWhat it detects:
| Category | Examples |
|---|---|
| Cloud credentials | AWS access keys, GCP service account keys, Azure connection strings |
| Source control | GitHub tokens (ghp_), GitLab tokens (glpat-), NPM tokens (npm_) |
| Payment | Stripe keys (sk_live_), Paystack keys |
| Communication | Slack tokens (xoxb-), Twilio credentials, SendGrid keys |
| Database | Connection strings with embedded passwords (postgresql://user:pass@host) |
| Auth | JWT tokens, generic API keys and bearer tokens |
| Nigerian PII | BVN/NIN (11-digit), card PANs, Nigerian phone numbers |
| Unknown secrets | High-entropy strings assigned to secret-like variables (--strict) |
Add to package.json for CI/CD:
{
"scripts": {
"scan": "anomira scan ./src --json"
}
}Exit code 0 = clean. Exit code 1 = violations found — use in CI to fail the build on leaked secrets.
Environment Variables
| Variable | Description |
|---|---|
| SENTINEL_API_KEY | Your Anomira API key |
| SENTINEL_APP_ID | Your Anomira app ID |
| SENTINEL_INGEST_URL | Ingest endpoint (from your dashboard) |
Configuration
| Option | Type | Default | Description |
|---|---|---|---|
| apiKey | string | — | Your Anomira API key (required) |
| appId | string | — | Your Anomira app ID (required) |
| ingestUrl | string | Anomira cloud | Ingest endpoint URL |
| debug | boolean | false | Log SDK activity to console |
| captureConsole | boolean | false | Forward console.* calls to the Logs dashboard |
| service | string | "app" | Service name tag for logs |
| detect.bruteForce | boolean | true | Detect brute force login attempts |
| detect.rateAbuse | boolean | true | Detect rate limit abuse |
| detect.pathTraversal | boolean | true | Detect path traversal attempts |
| detect.xss | boolean | true | Detect XSS in request bodies |
| detect.scanDetection | boolean | true | Detect scanner/bot probing |
| detect.geoVelocity | boolean | true | Detect impossible travel between logins |
Graceful Shutdown
Always flush pending events before your process exits:
process.on("SIGTERM", async () => {
await sentinel.flush();
process.exit(0);
});License
MIT
