payload-security
Audit any Payload CMS instance for the misconfigurations that actually leak data — collections readable without auth, field-level leaks (apiKey / email / hash), user/login enumeration, open first-user registration, and GraphQL introspection — 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 payload-security --url https://your-payload.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 access-control fixes.

$ npx payload-security --url https://cms.example.com
1 critical, 1 high, 1 medium — 3 CONFIRMED via anonymous probe
CRITICAL /api/posts readable without auth — 128 docs reachable
CRITICAL /api/users leaks apiKey, email to anonymous reads
MEDIUM /api/graphql GraphQL introspection enabled in production
Why this exists
Payload is one of the fastest-growing TypeScript-native headless CMSs (now part
of Vercel) — and it is not secure-by-default. Every collection's
access.read must be set explicitly; the REST API at /api/{slug} and GraphQL
at /api/graphql are exposed automatically. Payload's own docs warn that
local-API operations override access control
and that custom endpoints are not authenticated by default.
The widely-shared 2026 write-up
Payload CMS Security Best Practices: Top 10 Threats & Mitigation Strategies
(u11d) puts it bluntly: "attackers scan APIs first, not your frontend" — and a
huge share of Payload projects ship without proper read access on their
collections.
The endpoint shape is predictable (/api/{kebab-slug}, /api/graphql), so
proving a leak anonymously is trivial. payload-security runs those checks and
confirms the real ones by issuing the exact unauthenticated request an
attacker would — so you triage facts, not maybes.
What it checks
| Collection readable without auth | critical | anonymous GET /api/{slug} returns docs |
Sensitive field leak (apiKey/email/hash/salt) | critical | a returned doc contains the field with a value |
/api/users auth-collection enumeration | high | anonymous GET /api/users returns user docs |
| Open first-user registration | high | /api/users reachable and reports totalDocs:0 |
| GraphQL introspection in prod | medium | __schema query answered at /api/graphql |
| GraphQL playground in prod | medium | /api/graphql-playground served live |
Usage
npx payload-security --url https://cms.example.com
npx payload-security --url https://cms.example.com --discover ./my-payload-app
npx payload-security --url https://cms.example.com --collections posts,media
npx payload-security --url https://cms.example.com --html report.html
npx payload-security --url https://cms.example.com --no-probe
Output 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.
Install (optional)
npm i -g payload-security
payload-security --url https://cms.example.com
Zero dependencies. Your data and credentials never leave your machine — every
request goes straight from the tool to your Payload instance.
Sister tools
Same active-probe philosophy for the rest of the backend stack, all MIT:
strapi-security ·
directus-security ·
supabase-security ·
pocketbase-security ·
firebase-security ·
appwrite-security ·
nhost-security ·
convex-security
License
MIT © Renzo Madueno