npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

sqlguardjs

v1.0.4

Published

Express middleware and CLI scanner for injection and cross-site scripting attempts

Readme

SQLGuardJS for Node.js

npm version Tests Node.js >=18 License: MIT npm downloads

Protect your Express app from injection and cross-site scripting attempts in under a minute.

SQLGuardJS is an Express request verification layer, middleware, and CLI scanner for common injection and cross-site scripting attempts. It runs in-process, combines normalization with structural token analysis, and does not call a database or external service.

30-Second Quick Start

npm install sqlguardjs
const express = require('express');
const { sqlguardjs } = require('sqlguardjs');

const app = express();
const guard = sqlguardjs();

app.use(express.json());
app.use(guard.global());

app.post('/login', guard.route(), (req, res) => {
  res.json({ ok: true });
});

app.listen(3000);

Test a blocked request with your own local security-test string:

curl "http://localhost:3000/login?id=<security-test-string>"

Before and After

Without SQLGuardJS:

Attacker -> Express route -> Application logic -> Database or HTML rendering

With SQLGuardJS:

Attacker -> SQLGuardJS -> Blocked with 403 if malicious, otherwise passed to the Express route.

Why global() and route() both exist

Express does not populate req.params until after a route is matched.

  • guard.global() checks body, query, headers, and cookies before routes.
  • guard.route() checks any request sources not already scanned, plus req.params and optional schemas after Express resolves a route.

Performance

SQLGuardJS scans decoded request data in memory. Actual latency depends on payload size, nesting depth, logging, and schema checks.

For bulk endpoints, lower maxFields and maxPayloadLength to the largest valid request shape, or use skip and validate that upload path separately.

SQLGuardJS scans Express-visible data, including plain objects, arrays, buffers, URLSearchParams, Map, and Set containers. Register body parsers before the guard, and expose custom webhook or multipart bytes as req.rawBody if your route parses the raw stream later. Unparsed request streams are not visible to any middleware that only reads req.body.

The detector uses weighted signatures plus structural SQL-fragment and browser pseudo-protocol analysis, so boolean predicates, stacked statements, metadata enumeration, and constructor-chain browser vectors are not tied to one exact spelling.

1.0.4 Bypass Hardening

This release tightens SQL detection for unterminated block-comment breakouts, VALUES-based set-operation probes, and oversized payloads that try to hide suspicious content past the initial scan window. Long strings are still bounded, but SQLGuardJS now samples both the beginning and end of oversized inputs instead of only the prefix.

Secure Router

Use secureRouter() when you want the router to handle both global request scanning and route-level parameter/schema checks automatically.

const { secureRouter } = require('sqlguardjs');

const router = secureRouter({
  logFormat: 'json',
  logAttacks: event => console.warn(JSON.stringify(event))
});

router.post('/login', {
  schema: {
    body: {
      allowed: ['email', 'password'],
      required: ['email', 'password']
    },
    query: []
  }
}, (req, res) => {
  res.json({ ok: true });
});

secureRouter() auto-wraps direct HTTP method registrations such as get, post, put, and all. For path-scoped router.use() or chained router.route() declarations, pass guard.route() explicitly.

Admin Logs

Admins can see detections by enabling logAttacks or onThreat. In production, send these events to your normal logger, cloud logs, SIEM, database, or alerting system.

app.set('trust proxy', 1);

app.use(guard.global({
  rateLimitKey: req => req.user?.id ? `${req.user.id}:${req.ip}` : req.ip,
  logFormat: 'json',
  logAttacks: event => console.warn(JSON.stringify(event)),
  onThreat(event) {
    console.warn(event.requestId, event.label, event.confidence, event.matchedSignalIds);
  },
  onCallbackError(error, context) {
    console.error('SQLGuardJS callback failed', context);
  }
}));

Sensitive fields such as passwords and tokens are redacted in payload previews by default. Use logFormat: 'json' for production log ingestion. Text logs escape carriage returns and newlines, but structured logs are safer for line-oriented parsers. Failures thrown by logAttacks, onThreat, and onLearningEvent are isolated from request handling. Use onCallbackError to monitor logging, alerting, or review-queue failures.

In dryRun mode, SQLGuardJS scans the full request instead of stopping at the first detection. The first detection is stored on req.sqlguardjs; all detections are stored on req.sqlguardjsDetections.

Repeated suspicious activity is handled by the existing rate-limit escalation settings. Payloads above suspiciousThreshold but below threshold are allowed at first; after maxSuspiciousRequests for the same rateLimitKey inside rateLimitWindowMs, SQLGuardJS emits rate_limit_escalation with reason repeated_suspicious_probe. This is not a persistent reputation score or blocklist.

Log Endpoint

SQLGuardJS can keep a bounded in-memory event list and expose it through an endpoint you mount inside your own admin area.

const guard = sqlguardjs({
  mode: 'log',
  logRequests: true,
  maxLogs: 500
});

app.use(guard.global());
app.get('/admin/sqlguard/logs', requireAdmin, guard.logsHandler());

The endpoint returns sanitized detection and learning events as JSON. Payload previews are truncated and sensitive fields such as passwords and tokens are redacted. Mount this route only behind your own authentication.

Use ?limit=50 to return only the newest events. You can also mount the default path with:

guard.mountLogs(app);

logsPath is only used by auto-mount helpers. Setting it by itself does not create a route; use guard.logsHandler(), guard.mountLogs(app), or secureRouter({ exposeLogs: true }).

With guard.mountLogs(app), logsPath is mounted directly on that app:

const guard = sqlguardjs({ logsPath: '/security/logs' });
guard.mountLogs(app);

This mounts GET /security/logs directly on app.

With secureRouter(), logsPath is mounted on that router, so any app.use() prefix becomes part of the final URL:

const router = secureRouter({
  exposeLogs: true,
  logsPath: '/security/logs'
});

app.use('/api', router);

This mounts GET /api/security/logs.

Final SQL Query Guard

For second-order injection risk, where stored data is later concatenated into SQL, use the final-query guard at the database boundary:

const { assertSafeSqlQuery } = require('sqlguardjs');

assertSafeSqlQuery(dynamicQuery);

Keep using parameterized queries. This guard fails closed if unsafe dynamic SQL reaches the sink.

Safe Learning Mode

app.use(guard.global({
  mode: 'log',
  learning: true,
  logRequests: true,
  onLearningEvent(event) {
    console.info(event.clusterKey, event.payloadPreview);
  }
}));

Learning mode records suspicious allowed payloads for human review. It does not auto-train or mutate rules.

Detection Levels

Use named levels when you do not want to tune numeric thresholds directly:

app.use(guard.global({ level: 'strict' }));
app.use(guard.global({ level: 'balanced' }));
app.use(guard.global({ level: 'permissive' }));
  • strict blocks lower-confidence signals.
  • balanced keeps the default behavior.
  • permissive observes high-confidence detections unless you explicitly set mode: 'block'.

False-Positive Suppression

Suppress known safe routes or parameters with allowlists:

app.use(guard.global({
  allowRoutes: ['/admin/search'],
  allowParams: ['query.q', 'body.description']
}));

Lower sensitivity for a specific endpoint without disabling the guard everywhere:

app.use(guard.global({
  level: 'strict',
  routeLevels: {
    '/search': 'balanced'
  }
}));

Route keys can be plain paths such as /search or method-qualified paths such as GET /search.

NestJS

For NestJS on the Express adapter, reuse the middleware directly:

const { nestjsMiddleware } = require('sqlguardjs');

consumer
  .apply(nestjsMiddleware({ level: 'balanced' }))
  .forRoutes('*');

If your project prefers class middleware:

const { createNestMiddleware } = require('sqlguardjs');

const SqlGuardMiddleware = createNestMiddleware({ mode: 'log' });

Traffic Tuning

Use evaluatePayloads() with labeled traffic samples to measure false positives before changing thresholds:

const { evaluatePayloads } = require('sqlguardjs');

const report = evaluatePayloads([
  { payload: 'hello world', label: 'benign' },
  { payload: '<security-test-string>', label: 'xss' }
]);

console.log(report.summary);

CLI

sqlguardjs scan "<security-test-string>"
sqlguardjs scan-file payloads.txt --format csv

CSV output escapes row-breaking newlines and prefixes spreadsheet-formula-leading cells for safer analyst reports.

This package is defense in depth. Keep using parameterized queries, safe ORM APIs, context-aware output encoding, HTML sanitization, CSP, and least-privilege database accounts.

Full documentation lives in the repository root README.