Skip to content

Authorization bypass: subscription data exposure + API key restricted site access bypass #898

@lighthousekeeper1212

Description

@lighthousekeeper1212

Summary

Two authorization issues in the Rybbit server:

1. Subscription Data Exposure (HIGH)

File: server/src/api/stripe/getSubscription.ts
Route: GET /stripe/subscription (registered with authOnly middleware)

The endpoint accepts an organizationId query parameter but only checks that the user is authenticated (via authOnly), not that they are a member of the specified organization. Any authenticated user can read any organization's subscription plan, monthly event count, billing period, and status.

Secure adjacent pattern: createCheckoutSession.ts correctly verifies owner role:

const memberResult = await db.select({ role: member.role })
  .from(member)
  .where(and(eq(member.userId, userId), eq(member.organizationId, organizationId)));
if (!memberResult.length || memberResult[0].role !== "owner") {
  return reply.status(403).send({ error: "Only organization owners can manage billing" });
}

2. API Key Bypasses Restricted Site Access (MEDIUM)

File: server/src/api/sites/getSitesFromOrg.ts

When authenticated via API key, req.user?.id is null, causing the restricted site access filter to be skipped. A member with hasRestrictedSiteAccess=true (intentionally limited to specific sites by an org admin) sees ALL sites when using an API key instead of session auth.

const userId = req.user?.id;  // NULL with API key auth
const memberRecord = memberCheck[0];  // undefined when userId is null
if (memberRecord?.role === "member" && memberRecord.hasRestrictedSiteAccess) {
  // This block NEVER reached with API key auth
}

Recommended Fix

  1. Add orgMember middleware to the subscription endpoint
  2. Resolve API key auth to populate req.user.id for consistent filtering

Reported responsibly per SECURITY.md.

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