Skip to content

Missing RBAC authorization on payment/billing API endpoints (1-of-N inconsistency)Β #2511

@lighthousekeeper1212

Description

@lighthousekeeper1212

Security Report: Missing RBAC on Payment Endpoints

Summary

All 3 payment API endpoints check team membership (throwIfNoTeamAccess) but skip RBAC permission enforcement (throwIfNotAllowed), unlike every other team-scoped endpoint.

Affected Endpoints

  1. POST /api/teams/[slug]/payments/create-checkout-session
  2. POST /api/teams/[slug]/payments/create-portal-link
  3. GET /api/teams/[slug]/payments/products

Root Cause (1-of-N Inconsistency)

Every other team-scoped endpoint (SSO, DSYNC, API keys, webhooks, invitations, members, team CRUD) consistently calls both:

  • throwIfNoTeamAccess(req, res) β€” verifies team membership
  • throwIfNotAllowed(teamMember, 'team_payments', ...) β€” enforces RBAC permissions

The payment routes only call the first, skipping RBAC. The RBAC configuration in lib/permissions.ts defines team_payments as an OWNER-only resource.

Example

Correct pattern (from pages/api/teams/[slug]/api-keys/index.ts):

const teamMember = await throwIfNoTeamAccess(req, res);
throwIfNotAllowed(teamMember, 'team_api_key', 'read');

Payment endpoint (from pages/api/teams/[slug]/payments/create-checkout-session.ts):

const teamMember = await throwIfNoTeamAccess(req, res);
// Missing: throwIfNotAllowed(teamMember, 'team_payments', 'create');

Impact

Any MEMBER or ADMIN of a team (not just OWNER) can:

  • Create Stripe checkout sessions (change subscription plan)
  • Generate Stripe billing portal links (view/modify payment methods, invoices)
  • View subscription and product data

The UI correctly hides the billing tab via client-side canAccess('team_payments', ...) checks, but direct API calls bypass this.

Recommended Fix

Add throwIfNotAllowed(teamMember, 'team_payments', 'create'|'read') to each payment endpoint handler, matching the pattern used by all other team resources.

Environment

  • Version: Latest (commit at time of audit)
  • Identified via: Static code analysis

Note

The rest of the auth/authz implementation is excellent β€” consistent RBAC enforcement, proper team membership validation, Zod schema validation, and privilege escalation protection via validateMembershipOperation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions