Strapi's flexibility as a headless CMS comes with significant security configuration responsibility. Here's how to harden your Strapi API for production.
Anay Pandya
1,542 words
Anay Pandya
Founder of ZeriFlow · 10 years fullstack engineering · About the author
Key Takeaways
Strapi security is a topic that deserves more attention than it typically gets in deployment tutorials. Strapi's default configuration is optimized for getting a working API fast — not for production security. Permissive CORS, no rate limiting, default JWT secrets, and publicly accessible content types are common issues in Strapi deployments that make it onto the internet before being properly hardened.
<div class="zf-stat-callout" style="background:#0d1117;border:1px solid rgba(16,185,129,0.25);border-left:3px solid #10b981;border-radius:4px;padding:16px 20px;margin:24px 0"> <p style="margin:0 0 4px;font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:0.15em;color:#10b981;font-family:monospace">ZeriFlow Data — 12,400+ sites analyzed</p> <p style="margin:0;font-size:13px;color:#e2e8f0;line-height:1.6;font-family:monospace">ZeriFlow scans show 27% of web APIs have overly permissive CORS configurations — accepting cross-origin requests from any domain via Access-Control-Allow-Origin: *, exposing authenticated endpoints.</p> </div>
Keep reading
Is your site actually secure?
Run a free check — 60 seconds
Check your site's security right now: Free ZeriFlow scan →
Strapi uses a .env file for all sensitive configuration. The stakes are high: this file contains your database connection string, JWT secrets, and API keys.
Non-negotiable `.env` hygiene rules:
.env to .gitignore immediately when creating a Strapi project. Verify with git check-ignore -v .env before your first commit.APP_KEYS value (Strapi uses this for session cookies and other internal signing): node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
API_TOKEN_SALT, ADMIN_JWT_SECRET, TRANSFER_TOKEN_SALT, and JWT_SECRET..env file on disk.Never use the example values from Strapi's documentation in production. They're in the documentation and therefore known to attackers.
# .env — generate these values, never use defaults
APP_KEYS=<base64_random>,<base64_random>
API_TOKEN_SALT=<base64_random>
ADMIN_JWT_SECRET=<hex_random>
JWT_SECRET=<base64_random>
TRANSFER_TOKEN_SALT=<base64_random>Strapi's default CORS configuration allows all origins (*) in development. In production, this must be changed.
Configure CORS in config/middlewares.ts:
export default [
'strapi::logger',
'strapi::errors',
{
name: 'strapi::security',
config: {
contentSecurityPolicy: {
useDefaults: true,
directives: {
'connect-src': ["'self'", 'https:'],
'img-src': ["'self'", 'data:', 'blob:', 'https://market-assets.strapi.io'],
'media-src': ["'self'", 'data:', 'blob:'],
upgradeInsecureRequests: null,
},
},
},
},
{
name: 'strapi::cors',
config: {
enabled: true,
headers: '*',
origin: ['https://yourfrontend.com', 'https://www.yourfrontend.com'],
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
credentials: true,
},
},
'strapi::poweredBy',
'strapi::query',
'strapi::body',
'strapi::session',
'strapi::favicon',
'strapi::public',
];Run a free ZeriFlow scan → on your public Strapi endpoint to check which security headers are present and whether your CORS configuration is leaking allowed origins in responses.
Multiple environments: Use Strapi's environment-specific config files (config/env/production/middlewares.ts) to have strict CORS in production while allowing localhost in development.
By default, Strapi has no rate limiting. An unprotected Strapi API is vulnerable to brute-force attacks against the authentication endpoints and credential stuffing against user accounts.
Install the rate limiting middleware:
Strapi doesn't include rate limiting out of the box. Add it via the koa2-ratelimit or strapi-plugin-rate-limiter approach:
npm install koa2-ratelimitConfigure in src/middlewares/ratelimit.ts:
import ratelimit from 'koa2-ratelimit';
export default (config, { strapi }) => {
return ratelimit.middleware({
...ratelimit.RateLimit.middleware({
interval: { min: 15 },
max: 100,
prefixKey: ({ ctx }) => `${ctx.request.ip}`,
}),
...config,
});
};Register it in config/middlewares.ts and apply stricter limits to auth endpoints:
// In a custom auth rate limiting middleware
// Target: /api/auth/local and /api/auth/local/register
// Limit: 5 attempts per 15 minutes per IPAt the infrastructure level (Nginx, Cloudflare), add rate limiting before requests reach Strapi entirely.
Strapi uses the strapi::security middleware (wrapping koa-helmet) to add security headers. By default, several key headers are set, but the configuration benefits from explicit tuning.
The strapi::security middleware in config/middlewares.ts corresponds to Helmet.js settings. The defaults include:
X-DNS-Prefetch-ControlX-Frame-Options: SAMEORIGINStrict-Transport-Security (if HTTPS detected)X-Content-Type-Options: nosniffX-XSS-Protection: 0 (disables legacy XSS filter)Content-Security-Policy (Strapi admin panel specific)The CSP defaults are configured for the Strapi admin panel UI — they allow the admin panel's assets to load. Your API endpoint responses typically don't need a CSP header (they return JSON), but responses that include rendered HTML do.
For production, verify headers are being set by running a ZeriFlow scan. Pay particular attention to HSTS — it requires HTTPS to be correctly configured in your proxy layer for Strapi to detect and set it.
Admin JWT Secret:
The ADMIN_JWT_SECRET signs JWT tokens for Strapi Admin panel sessions. If this secret is weak or known (e.g., the documentation example), an attacker who obtains a valid token can forge tokens for any admin account.
Use a minimum 256-bit random secret:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"Rotate this secret if you suspect it has been exposed. Rotation invalidates all existing admin sessions, so coordinate with your team.
Users-Permissions plugin:
The users-permissions plugin handles end-user registration and authentication for your API. Key settings:
/api/auth/local/register). In the Strapi admin panel: Settings → Users & Permissions Plugin → Advanced Settings → Enable email confirmation and consider disabling the register endpoint entirely via a custom middleware if not needed.Every Strapi content type has a Permissions matrix in Settings → Users & Permissions Plugin → Roles → Public. By default in older Strapi versions, some content types might have public find and findOne access enabled.
Review and restrict public role permissions:
API tokens:
For headless CMS use cases where your frontend fetches content via the Strapi API, use API tokens (Settings → API Tokens → Create new API token) instead of exposing the admin credentials. Create scoped read-only tokens for your frontend and full-access tokens only where needed.
Set token expiry dates — non-expiring tokens are a risk if exposed.
Route-level protection:
For custom controller routes, use the auth: { scope: [...] } configuration or add authentication middleware to individual routes:
// src/api/article/routes/article.ts
export default {
routes: [
{
method: 'GET',
path: '/articles',
handler: 'article.find',
config: {
auth: false, // Public
},
},
{
method: 'POST',
path: '/articles',
handler: 'article.create',
config: {
auth: {
scope: ['api::article.article.create'],
},
},
},
],
};### Q: Is it safe to expose a Strapi API publicly on the internet? A: Yes, but only after hardening. A default Strapi install with no rate limiting, permissive CORS, and weak secrets should not be publicly exposed. After applying the hardening in this guide — restrictive CORS, rate limiting, locked permissions, strong secrets — a public Strapi API is appropriate for production use.
### Q: How do I check what my Strapi API endpoint is leaking in its response headers? A: Run a ZeriFlow scan on your Strapi API's public URL. It checks for the presence and configuration of all security headers, TLS settings, and cookie flags.
### Q: Should I use Strapi Cloud vs self-hosted for better security? A: Strapi Cloud handles infrastructure security (SSL, DDoS, platform updates) similar to other managed hosting platforms. Self-hosted gives you more control (custom middleware, server hardening) but requires more operational overhead. Either can be made secure — the application-level security (permissions, secrets, CORS) is identical on both.
### Q: What's the default admin password after Strapi installation? A: There is no default password — Strapi requires you to create an admin account during the first-run setup wizard. There is no backdoor or default credential. However, if you deployed Strapi on a public URL without completing setup, the setup wizard is publicly accessible — complete it immediately and then consider restricting the admin path via IP allowlist.
### Q: How do I prevent Strapi from leaking its version in response headers?
A: By default, Strapi includes an X-Powered-By: Strapi header. Remove it by configuring the poweredBy middleware: in config/middlewares.ts, replace 'strapi::poweredBy' with { name: 'strapi::poweredBy', config: { poweredBy: false } }.
Strapi is an excellent headless CMS, but its out-of-the-box configuration leaves several critical security gaps for production deployments. Strong, unique secrets across all environment variables, restrictive CORS to known origins, rate limiting on authentication endpoints, reviewed public API permissions, and proper security headers via the middleware configuration together create a production-ready security posture.
Validate your Strapi endpoint's external security footprint with an automated scan.
Run a free ZeriFlow scan → — 60 seconds, no credit card.
<!-- zf-internal-links -->
Related resources
Website Vulnerability Scanner
Run a broader website security audit across headers, TLS, DNS, cookies, SEO, and disclosure checks.
Security Headers Checker
Check CSP, HSTS, X-Frame-Options, and other response headers.
SSL Checker
Review TLS certificate, HTTPS, and transport security signals.
DMARC Checker
Validate email authentication records for domain spoofing protection.
CSP Checker
Review Content-Security-Policy coverage and common gaps.
June 24, 2026
Best Security Tools for AI Startups
Monitor your security score
Schedule recurring scans and catch regressions after deployments.