@appwarden/middleware
@appwarden/middleware is open source software that can be installed on your Cloudflare or Vercel-hosted website to enable Appwarden to quarantine your website during a security incident. Read the Core Features and Installation sections to learn more.
For a guided setup, start with Protect your Cloudflare project with Appwarden for Cloudflare deployments or Protect your Vercel project with Appwarden for Vercel deployments. If you are configuring protected hostnames or CSP behavior, take a look at the domain configuration guide and Content Security Policy guide.
- Discord Integration: Quarantine your website via Discord commands (
/quarantine [un]lock) - Instant Quarantine: Immediately redirects all visitors to a lock page when activated to stop in progress attacks.
- Nonce-based Content Security Policy (See Feature Compatibility): Deploy a nonce-based Content Security Policy (CSP) using HTML rewriting on Cloudflare where supported.
- Minimal Runtime Overhead: Negligible performance impact by using
event.waitUntilfor status checks
The table below summarizes which Appwarden features are available on each platform, including quarantine enforcement and Content Security Policy (CSP) support (with or without nonces).
| Platform / Adapter | Package / entrypoint | Quarantine | CSP | CSP Nonce |
|---|---|---|---|---|
| Cloudflare – Universal middleware | @appwarden/middleware/cloudflare | ✅ | ✅ | ✅ |
| Cloudflare – Astro | @appwarden/middleware/cloudflare/astro | ✅ | ✅ | ✅ |
| Cloudflare – React Router | @appwarden/middleware/cloudflare/react-router | ✅ | ✅ | ✅ |
| Cloudflare – TanStack Start | @appwarden/middleware/cloudflare/tanstack-start | ✅ | ✅ | ✅ |
| Cloudflare – Next.js (OpenNext adapter) | @appwarden/middleware/cloudflare/nextjs | ✅ | ✅ | ❌ |
| Vercel - Universal middleware | @appwarden/middleware/vercel | ✅ | ✅ | ❌ |
Nonce-based CSP requires HTML rewriting and is only available on Cloudflare. Next.js on Cloudflare (OpenNext) and Vercel Edge Middleware apply CSP headers only and do not support nonces. If you are using Next.js on Cloudflare, please use the Cloudflare Universal middleware for CSP nonce support.
The following options are shared across the Cloudflare and Vercel middleware bundles.
The path or route (for example, /maintenance) to redirect users to when the domain is quarantined.
This should be a working page on your site, such as a maintenance or status page, that
explains why the website is temporarily unavailable.
Controls the Content Security Policy headers that Appwarden adds. This configuration is optional—if not provided, no CSP header will be applied.
When provided, both mode and directives are required:
-
modecontrols how the CSP is applied:"disabled"– no CSP header is sent."report-only"– sends theContent-Security-Policy-Report-Onlyheader so violations are reported (for example in the browser console) but not blocked."enforced"– sends theContent-Security-Policyheader so violations are actively blocked.
When developing or iterating on your CSP, we recommend starting with
"report-only"so you can identify and fix violations before switching to"enforced". -
directivesis an object whose keys are CSP directive names and whose values are arrays of allowed sources. For example:contentSecurityPolicy: {mode: "enforced",directives: {"script-src": ["'self'", "{{nonce}}"],"style-src": ["'self'", "{{nonce}}"],},}
To add a nonce to a directive (See Feature Compatibility), include the "{{nonce}}" placeholder in the list of sources.
The Appwarden API token used to authenticate requests to the Appwarden API. See the API token management guide for details on creating and managing your token.
Treat this token as a secret (similar to a password): do not commit it to source control and store it in environment variables or secret management where possible. Appwarden stores API tokens using AES-GCM encryption and does not display them after creation.
The URL or connection string of the cache provider (for example, Upstash or Vercel Edge Config) that stores the quarantine status for your domain. See the Vercel integration guide for cache provider configuration details.
A Vercel API token that Appwarden uses to manage the Vercel Edge Config cache provider that synchronizes the quarantine status of your domain. See the Vercel integration guide for cache provider configuration details.
Appwarden never stores or logs your Vercel API token; it is used only to manage the quarantine status cache for your domain.
Compatible with websites powered by Cloudflare or Vercel.
For more background and advanced configuration, see the Appwarden documentation.
The Universal Middleware (@appwarden/middleware/cloudflare) is the recommended way to install Appwarden on Cloudflare. The easiest way to deploy this universal middleware is via our build-cloudflare-action; see the Cloudflare integration guide for workflow details. If you prefer to manage your own Cloudflare Worker instead of using the GitHub Action, you can mount the universal Cloudflare middleware directly using the @appwarden/middleware/cloudflare bundle:
import { createAppwardenMiddleware } from "@appwarden/middleware/cloudflare"
const appwardenHandler = createAppwardenMiddleware((cloudflare) => ({ debug: cloudflare.env.DEBUG, lockPageSlug: cloudflare.env.APPWARDEN_LOCK_PAGE_SLUG, appwardenApiToken: cloudflare.env.APPWARDEN_API_TOKEN, contentSecurityPolicy: { mode: cloudflare.env.CSP_MODE, directives: cloudflare.env.CSP_DIRECTIVES, },}))
export default { fetch(request: Request, env: CloudflareEnv, ctx: ExecutionContext) { return appwardenHandler(request, env, ctx) },}See the Cloudflare integration docs on appwarden.io for environment variable setup and deployment details.
If you cannot use build-cloudflare-action, you can mount Appwarden inside your application using framework-specific adapters.
Currently, framework adapters do not automatically reflect your Appwarden domain configuration. You must manually provide the
lockPageSlugandcontentSecurityPolicyconfiguration in your code.
import { sequence } from "astro:middleware"import { createAppwardenMiddleware } from "@appwarden/middleware/cloudflare/astro"
const appwarden = createAppwardenMiddleware((cloudflare) => ({ lockPageSlug: cloudflare.env.APPWARDEN_LOCK_PAGE_SLUG, appwardenApiToken: cloudflare.env.APPWARDEN_API_TOKEN, debug: cloudflare.env.DEBUG, contentSecurityPolicy: { // See Configuration > contentSecurityPolicy section for details mode: "report-only", directives: { "default-src": ["'self'"], }, },}))
export const onRequest = sequence(appwarden)See the Astro + Cloudflare guide for more details.
- Set
future.v8_middleware: truein yourreact-router.config.tsfile
import { env } from "cloudflare:workers"import { createAppwardenMiddleware } from "@appwarden/middleware/cloudflare/react-router"
export const middleware = [ createAppwardenMiddleware(() => ({ lockPageSlug: env.APPWARDEN_LOCK_PAGE_SLUG, appwardenApiToken: env.APPWARDEN_API_TOKEN, // "debug" can be a string or boolean; the schema will normalize it debug: env.DEBUG, // "directives" can be a JSON string or an object; the schema will parse it contentSecurityPolicy: { // See Configuration > contentSecurityPolicy section for details mode: "report-only", directives: { "default-src": ["'self'"], }, }, })),]See the React Router + Cloudflare guide for more details.
import { createMiddleware } from "@tanstack/start"import { env } from "cloudflare:workers"import { createAppwardenMiddleware } from "@appwarden/middleware/cloudflare/tanstack-start"
const appwardenMiddleware = createMiddleware().server( createAppwardenMiddleware(() => ({ lockPageSlug: env.APPWARDEN_LOCK_PAGE_SLUG, appwardenApiToken: env.APPWARDEN_API_TOKEN, debug: env.DEBUG, // Accepts string or boolean contentSecurityPolicy: { // See Configuration > contentSecurityPolicy section for details mode: "report-only", directives: { "default-src": ["'self'"], }, }, })),)
export const startInstance = createStart(() => ({ requestMiddleware: [appwardenMiddleware],}))See the TanStack Start + Cloudflare guide for more details.
// middleware.ts or proxy.tsimport { createAppwardenMiddleware } from "@appwarden/middleware/cloudflare/nextjs"
export const config = { matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],}
export default createAppwardenMiddleware((cloudflare) => ({ lockPageSlug: cloudflare.env.APPWARDEN_LOCK_PAGE_SLUG, appwardenApiToken: cloudflare.env.APPWARDEN_API_TOKEN, debug: cloudflare.env.DEBUG, // Headers-only CSP (no HTML rewriting, no nonce support; do not use `{{nonce}}` here) contentSecurityPolicy: { // See Configuration > contentSecurityPolicy section for details mode: "enforced", directives: { "default-src": ["'self'"], }, },}))This adapter applies CSP headers only before origin (no HTML rewriting, no nonce injection). Nonce-based CSP ({{nonce}}) is not supported in this adapter; CSP directives must not include {{nonce}}.
To use Appwarden as Vercel Edge Middleware, use the @appwarden/middleware/vercel bundle:
// middleware.ts (Next.js app on Vercel)import { createAppwardenMiddleware } from "@appwarden/middleware/vercel"
const appwardenMiddleware = createAppwardenMiddleware({ // Edge Config or Upstash KV URL cacheUrl: process.env.APPWARDEN_CACHE_URL!, // Required when using Vercel Edge Config vercelApiToken: process.env.APPWARDEN_VERCEL_API_TOKEN!, appwardenApiToken: process.env.APPWARDEN_API_TOKEN!, lockPageSlug: "/maintenance", contentSecurityPolicy: { // See Configuration > contentSecurityPolicy section for details mode: "report-only", directives: { "default-src": ["'self'"], }, },})
export default appwardenMiddlewareNonce-based CSP ({{nonce}}) is not supported in Vercel Edge Middleware; CSP directives must not include {{nonce}}.
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes using the Conventional Commits format
- This project enforces commit message format with commitlint
- Examples:
feat: add new featurefix: resolve issue with Xdocs: update READMEchore: update dependenciestest: add tests for feature X
- Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
# Install dependenciespnpm install
# Build the packagepnpm build
# Run testspnpm testPlease review our security policy for details on how we handle vulnerabilities and how to report a security issue.
This package is published with npm trusted publishers, to prevent npm token exfiltration, and provenance enabled, which provides a verifiable link between the published package and its source code. For more information, see npm provenance documentation.
- This project uses Conventional Commits and automated release tooling to keep versions and the changelog up to date.
- Patch releases may include bug fixes and internal maintenance or dependency updates (for example, Cloudflare Workers types, Wrangler, and GitHub Action tooling). New features are shipped in minor releases.
- See
CHANGELOG.mdfor the complete release history.
This project is licensed under the MIT License - see the LICENSE file for details.