
Security News
Socket Releases Free Certified Patches for Critical vm2 Sandbox Escape
A critical vm2 sandbox escape can allow untrusted JavaScript to break isolation and execute commands on the host Node.js process.
@tumull/shield
Advanced tools
Rate limiting, bot detection, and brute force protection for Node.js apps. Works with Next.js, Express, Fastify, Hono, or plain http. No external dependencies in the core.
Most rate limiting libs are either too simple (fixed window, no bot detection) or tied to a paid service. Shield gives you sliding window, token bucket, bot detection, brute force protection, and per-route config — all in one package, for free, with zero lock-in.
npm install @tumull/shield
// middleware.ts
import { shield } from '@tumull/shield'
export default shield({
limit: 100,
window: '1m',
})
export const config = {
matcher: '/api/:path*',
}
That's basically it. Your API routes are rate-limited now.
import express from 'express'
import { shieldExpress } from '@tumull/shield'
const app = express()
app.use(shieldExpress({ limit: 100, window: '1m' }))
import Fastify from 'fastify'
import { shieldFastify } from '@tumull/shield'
const app = Fastify()
app.register(shieldFastify, { limit: 100, window: '1m' })
import { Hono } from 'hono'
import { shieldHono } from '@tumull/shield'
const app = new Hono()
app.use('*', shieldHono({ limit: 100, window: '1m' }))
import http from 'node:http'
import { shieldNode } from '@tumull/shield'
const limiter = shieldNode({ limit: 100, window: '1m' })
http
.createServer(async (req, res) => {
if (await limiter(req, res)) return // blocked
res.writeHead(200)
res.end('ok')
})
.listen(3000)
shield({
limit: 100, // requests per window
window: '1m', // "30s", "1m", "5m", "1h", "1d"
block: '15m', // how long to block after exceeding limit
algorithm: 'sliding-window', // or 'fixed-window', 'token-bucket'
// different limits for different routes
routes: {
'/api/auth/login': { limit: 5, window: '5m', block: '30m' },
'/api/public/*': { limit: 500, window: '1m' },
'/api/private/*': { allowlistGeo: ['US', 'CA'] },
'/api/webhook/*': { skip: true },
},
// custom key (default: client IP)
key: (req) => req.headers.get('x-api-key') ?? extractIP(req),
store: 'memory', // default. also supports Redis, Upstash
botDetection: true,
blockBots: ['scrapy', 'curl'],
allowlist: ['127.0.0.1'],
// country-level controls (ISO codes)
allowlistGeo: ['US', 'CA'],
blocklistGeo: ['RU'],
wafEnabled: true,
wafRules: [
{ target: 'query', operator: 'regex', value: 'union\\s*select', flags: 'i' },
{ target: 'path', value: '/admin' },
],
blocklist: [],
headers: true, // X-RateLimit-* headers
onLimit: (req, retryAfter) =>
new Response(JSON.stringify({ error: 'Slow down' }), { status: 429 }),
})
Full config reference → docs/configuration.md
Memory (default) — no setup, works everywhere. LRU eviction keeps memory bounded.
import { shield, MemoryStore } from '@tumull/shield'
shield({ store: new MemoryStore({ maxSize: 10_000 }) })
Redis — for multi-instance / production setups.
import { RedisStore } from '@tumull/shield/stores/redis'
import Redis from 'ioredis'
shield({ store: new RedisStore({ client: new Redis(process.env.REDIS_URL) }) })
Upstash — HTTP-based, works on the edge (Vercel Edge, Cloudflare Workers).
import { UpstashStore } from '@tumull/shield/stores/upstash'
shield({
store: new UpstashStore({
url: process.env.UPSTASH_REDIS_URL!,
token: process.env.UPSTASH_REDIS_TOKEN!,
}),
})
More details → docs/stores.md
| Algorithm | What it does | Good for |
|---|---|---|
sliding-window | Weighted average of current + previous window | Most apps (default) |
fixed-window | Simple counter, resets on interval | High throughput |
token-bucket | Tokens refill at constant rate | Bursty traffic |
More details → docs/algorithms.md
When headers: true (default):
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 73
X-RateLimit-Reset: 1708934400
When blocked → 429 Too Many Requests with Retry-After header.
| Shield | express-rate-limit | @upstash/ratelimit | Arcjet | |
|---|---|---|---|---|
| Next.js middleware | ✅ | ❌ | ✅ | ✅ |
| Edge runtime | ✅ | ❌ | ✅ | ✅ |
| Zero deps | ✅ | ✅ | ❌ | ❌ |
| Sliding window | ✅ | ❌ | ✅ | ✅ |
| Bot detection | ✅ | ❌ | ❌ | ✅ |
| Brute force | ✅ | ❌ | ❌ | ✅ |
| Per-route config | ✅ | manual | ❌ | ✅ |
| Free | âś… | âś… | freemium | freemium |
See CONTRIBUTING.md.
MIT — TUMULL I.N.C.
FAQs
Drop-in API rate limiting & DDoS protection for Node.js/Next.js
We found that @tumull/shield demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
A critical vm2 sandbox escape can allow untrusted JavaScript to break isolation and execute commands on the host Node.js process.

Research
Five malicious NuGet packages impersonate Chinese .NET libraries to deploy a stealer targeting browser credentials, crypto wallets, SSH keys, and local files.

Security News
pnpm 11 turns on a 1-day Minimum Release Age and blocks exotic subdeps by default, adding safeguards against fast-moving supply chain attacks.