Audit any Strapi CMS for the misconfigurations that actually leak data — public-role read exposure, CORS reflection, user enumeration, GraphQL introspection, and the relational-populate admin oracle — and prove each one live with an anonymous probe. Other checklists tell you what might be wrong; this fetches the bytes and shows you what is.
⚡ Run it in one line, no admin token, no install:
npx strapi-security --url https://your-strapi.example.com
🤝 Want it done for you? Fixed-scope audit — $99 / 24h: I verify each finding live and send a written report with the exact config fixes.
$ npx strapi-security --url https://cms.example.com
1 critical, 2 high, 0 medium — 3 CONFIRMED via anonymous probe
CRITICAL /api/articles public-role read enabled — 1,204 rows reachable
HIGH CORS Origin reflected → cross-site credentialed reads
HIGH /api/users user list exposed (username + email)
Strapi powers a huge share of headless-CMS deployments, and the default
Users & Permissions model makes one mistake very easy: leaving find/findOne
enabled for the Public role. The result is an API anyone can read. 2026
alone brought a cluster of data-exposure CVEs around public endpoints
(CVE-2026-27886 relational
filtering oracle, CORS reflection, lookup-operator private-field leaks).
strapi-security checks for these and confirms the real ones by issuing the
exact anonymous request an attacker would — so you triage facts, not maybes.
| Check | Severity | How it's confirmed |
|---|---|---|
| Public-role read on a content-type | critical | anonymous GET /api/{collection} returns rows |
| CORS reflects arbitrary Origin | high | sends a foreign Origin, sees it echoed in Access-Control-Allow-Origin |
/api/users user enumeration |
high | anonymous GET /api/users returns the user list |
| Relational-populate admin oracle | high | ?populate=createdBy leaks admin fields |
| GraphQL introspection in prod | medium | __schema query answered on /graphql |
| Open first-admin registration | critical | /admin/init reports hasAdmin:false |
# Probe a live instance (guesses common collection names)
npx strapi-security --url https://cms.example.com
# Learn your exact collection names from your local repo, then probe
npx strapi-security --url https://cms.example.com --discover ./my-strapi-app
# Probe specific collections
npx strapi-security --url https://cms.example.com --collections articles,authors
# Write a shareable HTML report
npx strapi-security --url https://cms.example.com --html report.html
# Static only (no requests sent)
npx strapi-security --url https://cms.example.com --no-probeOutput is JSON on stdout (pipe it into CI) and a one-line summary on stderr.
Exit is non-zero only on usage errors — gate your pipeline on the JSON summary.
npm i -g strapi-security
strapi-security --url https://cms.example.comZero dependencies. Your data and credentials never leave your machine — every request goes straight from the tool to your Strapi instance.
Same active-probe philosophy for the rest of the backend stack, all MIT:
supabase-security · pocketbase-security · firebase-security · appwrite-security · nhost-security · directus-security · convex-security · hasura-security · payload-security
MIT © Renzo Madueno
📚 Part of Awesome Backend Security Auditors — the full collection of keyless active-probe auditors.