Zum Inhalt springen

payload-security-scan

Type Skill
Plugin awl-web · v0.0.6
Invoke /awl-web:payload-security-scan
Source plugins/awl-web/skills/payload-security-scan/SKILL.md

Scans a Payload CMS project for broken access control — missing or permissive collection/field/global access functions, unprotected endpoints, hooks that leak data. Use when asked to “review payload security”, “check access control”, “audit payload collections”, “security scan”, or before releasing a Payload project. Not for general code review (use awl-general review).

Trigger phrases: review payload security · check access control · audit payload collections · security scan

Scan a Payload CMS project for access control vulnerabilities. Based on OWASP Top 1: Broken Access Control.

Use when asked to “security scan”, “audit endpoints”, “scan payload project”, “check access controls”, or “audit permissions”.

Check all collection and global configs in src/collections/**/*.ts and src/globals/**/*.ts:

  1. Access config audit — For each collection/global, document the access property:

    • create, read, update, delete — who has each permission?
    • Flag collections where read or update is open to all authenticated users (especially if signup is open)
    • Flag collections with no access config (defaults to admin-only, but verify)
  2. Field-level permissions — Check for sensitive fields without field-level access control:

    • Permission fields on user models: isAdmin, role, roles, permissions, userType
    • A user MUST NOT be able to increase their own permissions (privilege escalation)
    • Sensitive data fields: API keys, secrets, 2FA secrets, tokens
    • Granting read or update on a collection grants access to ALL fields unless field-level access is set
    • Check if @awl/payload-access-policies is in use, recommend to use it if not
  3. Auth configuration — Check src/collections/Users.ts (or equivalent):

    • Is auth: true set?
    • Can anyone sign up, or is it invite/admin-only? If not clear, ask the user.
    • If open signup + broad collection access = anyone can read/write data

Search three locations for custom API endpoints (relative to payload dir):

  1. Collection config endpointssrc/collections/**/*.ts

    • Grep for endpoints property in collection configs
    • These register as /api/{collection-slug}/{endpoint-path}
  2. Next.js route handlerssrc/app/**/api/**/route.ts

    • Exclude auto-generated Payload routes:
      • [...slug]/route.ts (REST catch-all)
      • graphql/route.ts
      • graphql-playground/route.ts
    • Each route.ts exports HTTP method handlers (GET, POST, etc.)
  3. Payload endpoint filessrc/endpoints/**/*.ts

    • Custom endpoints registered in payload.config.ts via endpoints: [...]
    • Check payload.config.ts to confirm which are active

Custom endpoints are publicly available by default — you MUST check each one for:

Control What to look for
Authentication payload.auth(), req.user check, bearer token validation, API key check
Authorization Role checks (hasRole, isAdmin), ownership verification, overrideAccess usage
Input validation Zod/Valibot schemas, manual param checks

Classify each endpoint:

  • admin — requires admin/specific role
  • authenticated — requires login but no role check
  • public — no authentication
  • secret — API key or secret param

Output a markdown report:

# Security Scan: {project-name}
## Auth Configuration
- Signup: open / invite-only / admin-only
- Auth method: session / JWT / external IdP
- Access policy package: yes/no
## Collection Access Controls
| Collection | Create | Read | Update | Delete | Sensitive Fields | Issues |
|-----------|--------|------|--------|--------|-----------------|--------|
## Custom Endpoints ({count})
| Method | Path | Auth | Validation | File |
|--------|------|------|------------|------|
## Findings
### Critical
| Location | Issue |
|----------|-------|
### High
| Location | Issue |
|----------|-------|
### Medium
| Location | Issue |
|----------|-------|
  • Making data available publicly when it shouldn’t be
  • Making data available/writeable for all authenticated users when anyone can sign up
  • Privilege escalation: user can change their own role/isAdmin/permissions field
  • Exposing sensitive data (API keys, secrets, tokens) via collection read access
  • Custom endpoints without any auth check (they default to public)
  • overrideAccess: true without proper upstream auth gating
  • Hardcoded secrets or fallback keys in endpoint auth
  • Critical: No auth on destructive/data-exposing endpoints; privilege escalation possible; hardcoded secrets; SSRF/injection vectors
  • High: Auth without RBAC on admin operations; missing ownership checks; sensitive fields without field-level access; open signup + broad collection access
  • Medium: Public endpoints triggering external API calls; missing input validation on write endpoints
  • Use sub-agents for Phase 1 + Phase 2 when scanning large projects
  • Auto-generated Payload routes ([...slug], graphql) use Payload’s built-in access control — focus audit on collection access configs instead
  • Always check WHO can authenticate before evaluating access controls
  • Check for @awl/payload-access-policies package (by Mich) — projects using it likely have better defaults