AIWAF for Node.js
Source and package versions
One AIWAF repository.
Python: py/aiwaf/ · Node.js: js/ · Rust/WASM: rust/ · Java: java/.
Source and canonical README.
Versions shown are the latest published releases; each package is versioned independently.
Current versions are aiwaf 1.1.8 (Python) and
aiwaf 1.1.5 (npm), with Rust/Python 0.2.7 and
WASM 0.2.5 and Java 1.3.5. Sandbox guides retain their separately pinned builds.
The current release is aiwaf 1.1.5 with the declared aiwaf-wasm ^0.2.5 dependency. Publish the matching WASM companion first. The native request engine still requires explicit registration and awaits initialization; a missing native API fails startup. Legacy adapters keep their separate configuration and execution path.
Offline training now uses WASM receipts to prevent handled historical requests from extending or recreating blocks after expiry or manual removal. Models still fit on history; enforcement uses fresh requests. Preserve node_training_evidence.json in the blocklist data directory, or set AIWAF_TRAINING_STATE_DIR to a durable shared directory. Invalid timestamps are excluded. Missing WASM APIs, corrupt receipts, and storage failures make training fail visibly. A crashed trainer can leave node_training_evidence.lock; confirm it has stopped before removing that lock directory. Block and receipt writes are separate, so a crash between them can require recovery.
The current reference tests use Node 22.18.0, Express 4, Fastify 5, and NestJS 11. These are tested configurations, not a claim that every framework version is supported. Use the framework and adapter matching your application. Next.js examples require Node API request/response objects; Edge middleware is not supported by this adapter.
Legacy blocklist request checks and listing are read-only. Explicit database cleanup checks expiry in the DELETE statement; CSV cleanup reads current rows under the same cross-process lock used by blocklist writes. A crash can leave <blocklist CSV path>.lock; confirm its writer has stopped before removing that directory. Lock acquisition fails after 60 seconds. Restart all old writers when upgrading. These fixes do not make the explicit native engine's per-worker state distributed.
For source development, use the committed lockfile with npm ci, run the coverage and real native checks, and audit the complete tree with npm audit. Read dependency versions and verification and native migration.
Native request pipeline
Native mode: Node release aiwaf 1.1.5 declares aiwaf-wasm ^0.2.5. Explicit native registration validates NativeRequestPipeline at startup; missing or incompatible support is an error. There is no JavaScript policy fallback for this engine. Installing the dependency does not switch an existing legacy middleware chain.
The explicit native adapter validates configuration once, then Rust/WASM owns geo/blocklist/keyword/structured SQL decisions, rate and flood counters, honeypot timing, UUID scores, anomaly history/model inference, keyword learning and CSV formatting. Node retains framework facts, bounded body parsing, response handling and filesystem writes with cached file descriptors. Existing integrations keep their legacy middleware path.
Read the native lifecycle, configuration, deployment and measurements, and migration.
How AIWAF works: system architecture
The CommonJS npm package is aiwaf, version 1.1.5, declared in js/package.json. Install with npm install aiwaf and import with require('aiwaf'). All adapters share the monorepo and root README.
Express quick start
const express = require('express');
const aiwaf = require('aiwaf');
const app = express();
app.use(express.json());
app.use(aiwaf({
AIWAF_MIDDLEWARES: ['auto'],
staticKeywords: ['.php', '.env', '.git'],
WINDOW_SEC: 10,
MAX_REQ: 20,
FLOOD_REQ: 40,
AIWAF_HEADER_VALIDATION: true,
AIWAF_METHOD_POLICY_ENABLED: true,
AIWAF_ALLOWED_METHODS: ['GET', 'POST', 'HEAD', 'OPTIONS']
}));
app.get('/', (req, res) => res.json({ protected: true }));
app.listen(3000);
Attach AIWAF after the body parser when honeypot rules inspect parsed form or JSON fields.
Framework entry points
| Framework | Entry point |
|---|---|
| Express | aiwaf(options) |
| Fastify | fastify.register(aiwaf.fastify, options) |
| Hapi | server.register({ plugin: aiwaf.hapi, options }) |
| Koa | app.use(aiwaf.koa(options)) |
| NestJS/Express | aiwaf.nest(options) or the Express middleware |
| NestJS/Fastify | app.register(aiwaf.fastify, options) |
| Next.js API routes | aiwaf.next(handler, options) |
| AdonisJS | aiwaf.adonis(options) |
| Sails.js | aiwaf.sails(options) |
Route policies
app.use(aiwaf({
AIWAF_PATH_RULES: [
{ PREFIX: '/health/', DISABLE: ['header_validation', 'rate_limit'] },
{ PREFIX: '/api/public/', RATE_LIMIT: { WINDOW: 60, MAX: 300 } }
]
}));
Applications can also use aiwaf.exempt, aiwaf.exemptFrom, aiwaf.only, and aiwaf.requireProtection to build route policies.
Generate an Express route manifest after routes are registered:
aiwaf.generateExpressManifest(app, '.aiwaf/paths.json');
Or generate one from a route list with the CLI:
cd js
npm run aiwaf -- manifest --framework express --routes routes.json --output .aiwaf/paths.json
Configuration and acceleration
| Area | Important options |
|---|---|
| Middleware | AIWAF_MIDDLEWARES, AIWAF_DISABLE_MIDDLEWARES, AIWAF_PATH_RULES |
| Rate limiting | WINDOW_SEC, MAX_REQ, FLOOD_REQ, cache |
| Headers | AIWAF_HEADER_VALIDATION, AIWAF_REQUIRED_HEADERS, AIWAF_HEADER_QUALITY_MIN_SCORE |
| Methods | AIWAF_METHOD_POLICY_ENABLED, AIWAF_ALLOWED_METHODS |
| Keywords | staticKeywords, AIWAF_ENABLE_KEYWORD_LEARNING, AIWAF_DYNAMIC_TOP_N |
| Honeypot | HONEYPOT_FIELD, timing settings |
| GeoIP | AIWAF_GEO_BLOCK_ENABLED, AIWAF_GEO_BLOCK_COUNTRIES, AIWAF_GEO_ALLOW_COUNTRIES |
| Models | AIWAF_MODEL_STORAGE, AIWAF_MODEL_PATH, AIWAF_MODEL_CACHE_KEY |
| Logging | AIWAF_MIDDLEWARE_LOGGING, AIWAF_MIDDLEWARE_LOG_PATH, DB/CSV options |
| WASM | AIWAF_WASM_VALIDATION, AIWAF_WASM_VALIDATE_RECENT |
AIWAF loads aiwaf-wasm when available and falls back to the JavaScript implementation when WASM initialization or conversion is not worthwhile. Small, object-heavy operations can be faster in JavaScript because crossing the JS/WASM boundary and serializing objects has a fixed cost. WASM is most useful for sufficiently large feature batches and model scoring workloads.
