πŸ“¦ Payload CMS Security Scanner - Find Leaks avatar

πŸ“¦ Payload CMS Security Scanner - Find Leaks

Pricing

from $4.65 / 1,000 security findings

Go to Apify Store
πŸ“¦ Payload CMS Security Scanner - Find Leaks

πŸ“¦ Payload CMS Security Scanner - Find Leaks

Probes a public Payload CMS instance for collections readable without auth. Default templates leave read access wide open during development.

Pricing

from $4.65 / 1,000 security findings

Rating

0.0

(0)

Developer

Renzo Madueno

Renzo Madueno

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

7 days ago

Last modified

Categories

Share

Payload CMS Security Scanner β€” Find public collection leaks

Every Payload CMS template I've checked (template-blog, template-website, template-ecommerce) ships with access: { read: () => true } on most collections so you can browse the API in development. That setting often makes it to production unchanged β€” and the moment it does, anyone with your CMS URL can list every record in users, orders, media, custom collections, you name it. This actor finds those leaks in 30 seconds.

Probes a public Payload CMS instance for collections readable without authentication. Sends /api/{collection}?limit=1 per collection. Returns counts + a verbatim curl reproducer per finding. Counts only β€” never row data.

Why this exists

Payload CMS uses per-collection access functions for authorization. The framework is excellent β€” but the defaults in every official template are permissive:

// from payloadcms/template-blog (default):
export const Posts: CollectionConfig = {
slug: 'posts',
access: {
read: () => true, // ← anyone can read all posts
},
// ...
};

That's fine for posts (you probably want them public). But the same () => true pattern is copy-pasted onto:

  1. users β€” anyone gets to enumerate emails, hashed passwords (yes, the hash + salt are returned), roles, login attempt counts
  2. orders/transactions β€” full purchase history, Stripe IDs, shipping addresses
  3. media β€” file metadata + the signed URLs to download them

This scanner probes ~30 common collection slugs plus any you pass as hints.

How to run

Either:

  1. Leave inputs empty + click Run for a DEMO sample report
  2. Provide your payloadUrl to scan your actual instance
{
"payloadUrl": "https://cms.your-domain.com",
"collectionHints": ["my-custom-collection"],
"outputFormat": "both"
}

What you get

  • HTML report (report.html in run's KV store): severity-coded findings, copy-pasteable curl reproducers, exact code change to fix each leaky collection
  • Dataset rows: one structured row per finding

Sample finding

[CRITICAL] users β€” readable anonymously
Total records: 2,891
Sample columns: id, email, name, role, createdAt, updatedAt, loginAttempts, lockUntil, hash, salt
Sensitive columns detected: email, hash, salt
Reproducer:
curl 'https://cms.your-domain.com/api/users?limit=1' -I

How to fix (code change, ~5 min per collection)

In your Payload config, for each leaky collection, set access.read:

// collections/Users.ts
import { CollectionConfig } from 'payload/types';
export const Users: CollectionConfig = {
slug: 'users',
access: {
read: ({ req: { user } }) => Boolean(user), // ← require auth
// or strict per-record:
// read: ({ req: { user } }) => ({ id: { equals: user?.id } }),
},
// ...
};

If the collection should be public (blog posts, product catalog), use Payload's field-level access control:

fields: [
{ name: 'title', type: 'text' }, // public
{ name: 'authorEmail', type: 'email',
access: { read: ({ req: { user } }) => Boolean(user) } }, // auth-only
],

Ethical use

Built and maintained by Renzo MadueΓ±o, founder of Rotate Pilot, aviation exam-prep software. More tools on GitHub.