Imported security middleware is actually wired in
Why it matters
When an AI coding assistant is prompted to "add security" or "rate-limit this API" it will reliably install helmet, express-rate-limit, csurf, csrf-csrf, or a CORS package, import the module at the top of a file, and then forget to actually register the middleware with the app. The package shows up in package.json, the import statement satisfies the grep-for-safety review instinct, and the code LOOKS defended — but without an app.use(helmet()), app.use(limiter), fastify.register(cors), or equivalent registration, none of the middleware runs on any request. Every response ships with no security headers, every endpoint accepts unbounded traffic, every state-changing POST is vulnerable to CSRF. OWASP A05 (Security Misconfiguration) is the exact mapping. This pattern is especially insidious because it passes visual code review — a human glance sees "imports helmet, imports rate-limit, looks fine" — and only deep inspection of the app-initialization code reveals that none of the middleware chain fired.
Severity rationale
High because every unapplied middleware represents a missing control that the code pretends to have — attackers get XSS-prone responses, unlimited request rates, and unprotected state mutations while reviewers believe the app is hardened.
Remediation
For every security middleware in package.json, register it in the app's initialization chain before route definitions:
// src/server.ts
import express from 'express';
import helmet from 'helmet';
import rateLimit from 'express-rate-limit';
import { doubleCsrf } from 'csrf-csrf';
const app = express();
app.use(helmet());
app.use(rateLimit({ windowMs: 60_000, max: 100 }));
const { doubleCsrfProtection } = doubleCsrf({ getSecret: () => process.env.CSRF_SECRET! });
app.use(doubleCsrfProtection);
// ... routes below
For Fastify use fastify.register(...); for Hono use app.use('*', ...). If the project is Next.js, helmet does not apply — configure headers in next.config.ts via the headers() export or in middleware.ts. Run security-hardening and api-security for deeper coverage including per-route rate limits, CSRF-token rotation policies, and CORS origin allowlists.
Detection
- ID:
security-middleware-applied - Severity:
high - What to look for: Check
package.jsonfor:helmet,express-rate-limit,csurf,csrf-csrf,next-csrf,cors(as middleware, not just response headers),express-session,passport,rate-limiter-flexible,@fastify/helmet,@fastify/rate-limit,@fastify/csrf-protection,hono/csrf,hono/secure-headers. For each present, grep for imports. For each imported middleware, confirm registration via.use(...)(Express/Hono/Koa) or.register(...)(Fastify) somewhere reachable from the app entry (src/server.ts,src/index.ts,src/app.ts,src/main.ts, or a router-setup file). - Pass criteria: Every middleware that is both in deps AND imported is also registered via the correct framework call.
- Fail criteria: Any middleware imported but not registered. Commented-out registration (
//orif (false)/if (NODE_ENV==='never')) does NOT count. Registration that disables the protection —rateLimit({ max: Infinity }),helmet({ contentSecurityPolicy: false, hsts: false, xssFilter: false, noSniff: false })— does NOT count. - Skip (N/A) when: No security-middleware packages in deps AND framework is Next.js / Astro / SvelteKit / Remix (where middleware is config-file-driven). Quote the dep list.
- Before evaluating, quote:
package.jsondeps + each middleware import (file:line) + the entry-point file. - Report even on pass:
"helmet: src/server.ts:3 imported, :12 registered via app.use(helmet())". - Detail on fail:
"helmet imported in src/server.ts:2, no app.use(helmet()) call anywhere — responses ship with no headers. express-rate-limit imported in src/routes/auth.ts:4, no .use(limiter)". - Remediation:
For Fastify:// src/server.ts import express from 'express'; import helmet from 'helmet'; import rateLimit from 'express-rate-limit'; const app = express(); app.use(helmet()); app.use(rateLimit({ windowMs: 60_000, max: 100 })); // ...routes belowfastify.register(...); Hono:app.use('*', ...). Next.js: configure headers innext.config.tsviaheaders()ormiddleware.ts. If a middleware is intentionally disabled, delete the import.
External references
- cwe · CWE-1173 — Improper Use of Validation Framework
- cwe · CWE-693 — Protection Mechanism Failure
- owasp:2021 · A05 — Security Misconfiguration
Taxons
History
- 2026-04-23·v1.0.0·Initial Phase 9.1 v3.1 Stack Scan promotion — imported-but-unwired security middleware is a pervasive AI scaffolding antipattern that defeats visual code review.·by phase-9-1-stack-scan-v3-1